關於 Go 並發程式設計 Mutex
友情提示:這篇文章大約需要閱讀 5分鐘45秒,不足之處請多指教,感謝你的閱讀。 我們比較常見的大型專案的設計中都會出現並發存取問題,並發就是為了解決資料的準確性,保證同一個臨界區的資料只能被一個執行緒進行操作,日常中使用到的並發場景也是很多的:
計數器:計數器結果不準確;
秒殺系統
:由於相同時間訪問量比較大,導致的超賣;- 用戶帳戶異常:同一時間支付導致的帳戶透支;
- buffer 資料異常:更新buffer 導致的數據混亂。
- 上面都是並發帶來的資料準確性的問題,決絕方案就是使用互斥鎖 ,也就是今天並發程式設計中的所要描述的Mutex 並發原語。
- 實作機制
互斥鎖 Mutex 是為了避免並發競爭建立的並發控制機制,其中有個「臨界區」的概念。
在並發程式設計過程中,如果程式中一部分資源或變數會被並發存取或修改,為了避免並發存取導致資料的不準確,這部分程式需要率先被保護起來,之後操作,操作結束後去除保護,這部分被保護的程式就叫做臨界區。
使用互斥鎖,限定臨界區只能同時由一個執行緒持有,若是臨界區此時被一個執行緒持有,那麼其他執行緒想進入到這個臨界區的時候,就會失敗或等待釋放鎖,持有此臨界區的執行緒退出,其他執行緒才有機會獲得這個臨界區。go mutex 臨界區示意圖
#Mutex 是Go 語言中使用最廣泛的同步原語,也稱為並發原語,解決的是並發讀寫共享資源,避免出現資料競爭data race 問題
。基本上使用
互斥鎖Mutex 提供了兩個方法Lock 和Unlock:進入到臨界區使用Lock 方法加鎖,退出臨界區使用Unlock 方法釋放鎖。
type Locker interface { Lock() Unlock()}func(m *Mutex)Lock()func(m *Mutex)Unlock()
當一個 goroutine 呼叫 Lock 方法取得到鎖後,其他 goroutine 會阻塞在 Lock 的呼叫上,直到目前取得到鎖的 goroutine 釋放鎖。
接下來是一個計數器的例子,是由100 個goroutine 對計數器進行累加操作,最後輸出結果:package mainimport (
"fmt"
"sync")func main() {
var mu sync.Mutex
countNum := 0
// 确认辅助变量是否都执行完成
var wg sync.WaitGroup // wg 添加数目要和 创建的协程数量保持一致
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
mu.Lock()
countNum++
mu.Unlock()
}
}()
}
wg.Wait()
fmt.Printf("countNum: %d", countNum)}
很多時候Mutex 並不是單獨使用的,而是嵌套在Struct 中使用,作為結構體的一部分,如果嵌入的struct 有多個字段,我們一般會把Mutex 放在要控制的字段上面,然後使用空格把欄位分隔開來。
甚至可以把取得鎖定、釋放鎖定、計數加一的邏輯封裝成一個方法。 package mainimport (
"fmt"
"sync")// 线程安全的计数器type Counter struct {
CounterType int
Name string
mu sync.Mutex
count uint64}// 加一方法func (c *Counter) Incr() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++}// 取数值方法 线程也需要受保护func (c *Counter) Count() uint64 {
c.mu.Lock()
defer c.mu.Unlock()
return c.count}func main() {
// 定义一个计数器
var counter Counter var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++ {
go func() {
defer wg.Done()
for j := 0; j < 1000; j++ {
counter.Incr()
}
}()
}
wg.Wait()
fmt.Printf("%d\n", counter.Count())}
登入後複製
package mainimport ( "fmt" "sync")// 线程安全的计数器type Counter struct { CounterType int Name string mu sync.Mutex count uint64}// 加一方法func (c *Counter) Incr() { c.mu.Lock() defer c.mu.Unlock() c.count++}// 取数值方法 线程也需要受保护func (c *Counter) Count() uint64 { c.mu.Lock() defer c.mu.Unlock() return c.count}func main() { // 定义一个计数器 var counter Counter var wg sync.WaitGroup wg.Add(100) for i := 0; i < 100; i++ { go func() { defer wg.Done() for j := 0; j < 1000; j++ { counter.Incr() } }() } wg.Wait() fmt.Printf("%d\n", counter.Count())}
思考問題
Q:你已經知道,如果Mutex 已經被一個goroutine 取得了鎖,其它等待中的goroutine 只能一直等待。那麼,等這個鎖釋放後,等待中的 goroutine 中哪一個會優先取得 Mutex 呢?A:FIFO,先來先服務的策略,Go 的goroutine 調度中,會維護一個保障goroutine 運行的隊列,當獲取到鎖的goroutine 執行完臨界區的操作的時候,就會釋放鎖,在佇列中排在第一位置的goroutine 會拿到鎖進行臨界區的操作。
#######################################################################################################
以上是關於 Go 並發程式設計 Mutex的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在Go中,可以使用gorilla/websocket包發送WebSocket訊息。具體步驟:建立WebSocket連線。傳送文字訊息:呼叫WriteMessage(websocket.TextMessage,[]byte("訊息"))。發送二進位訊息:呼叫WriteMessage(websocket.BinaryMessage,[]byte{1,2,3})。

在Go中,函數生命週期包括定義、載入、連結、初始化、呼叫和返回;變數作用域分為函數級和區塊級,函數內的變數在內部可見,而區塊內的變數僅在區塊內可見。

Go和Go語言是不同的實體,具有不同的特性。 Go(又稱Golang)以其並發性、編譯速度快、記憶體管理和跨平台優點而聞名。 Go語言的缺點包括生態系統不如其他語言豐富、文法更嚴格、缺乏動態類型。

在Go中,可以使用正規表示式比對時間戳記:編譯正規表示式字串,例如用於匹配ISO8601時間戳記的表達式:^\d{4}-\d{2}-\d{2}T \d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-][0-9]{2}:[0-9]{2})$ 。使用regexp.MatchString函數檢查字串是否與正規表示式相符。

記憶體洩漏會導致Go程式記憶體不斷增加,可通過:關閉不再使用的資源,如檔案、網路連線和資料庫連線。使用弱引用防止記憶體洩漏,當物件不再被強引用時將其作為垃圾回收目標。利用go協程,協程棧記憶體會在退出時自動釋放,避免記憶體洩漏。

在Go中傳遞map給函數時,預設會建立副本,對副本的修改不影響原map。如果需要修改原始map,可透過指標傳遞。空map需小心處理,因為技術上是nil指針,傳遞空map給期望非空map的函數會發生錯誤。

在Golang中,錯誤包裝器允許你在原始錯誤上追加上下文訊息,從而創建新錯誤。這可用於統一不同程式庫或元件拋出的錯誤類型,簡化偵錯和錯誤處理。步驟如下:使用errors.Wrap函數將原有錯誤包裝成新錯誤。新錯誤包含原始錯誤的上下文資訊。使用fmt.Printf輸出包裝後的錯誤,提供更多上下文和可操作性。在處理不同類型的錯誤時,使用errors.Wrap函數統一錯誤類型。

對並發函數進行單元測試至關重要,因為這有助於確保其在並發環境中的正確行為。測試並發函數時必須考慮互斥、同步和隔離等基本原理。可以透過模擬、測試競爭條件和驗證結果等方法對並發函數進行單元測試。
