經過Mutex和信道處理競態條件。併發
當程序併發運行時,多個協程不該該同時訪問那些修改共享資源的代碼,這些修改共享資源的代碼稱爲臨界區。線程
Go中經過Mutex能夠避免同時訪問臨界區,從而避免了競態條件。code
Mutex提供了一種鎖機制,能夠確保某個時刻只有一個協程在臨界區運行,防止出現競態條件。server
Mutex中定義了兩個方法:Lock和Unlock。 Lock和Unlock之間的代碼只能由一個協程執行,避免了競態條件。協程
mutex.Lock() x = x+1 mutex.Unlock()
Var x = 0 func increment(wg *sync.WaitGroup, m *sync.Mutex){ m.Lock() x = x+1 m.Unlock() wm.Done() } func main(){ var w sync.WaitGroup var m sync.Mutex for I := 0; I < 1000; I++{ w.Add(1) go increment(&w, &m) } w.Wait() }
Select用於在多個發送/接收信道中進行選擇,select語句會一直阻塞,直到發送/接收操做準備就緒。資源
若是有多個信道操做準備就緒,select會隨機選擇其中之一執行。rem
output1 := make(chan string) output2 := make(chan string) go server1(output1) go server2(output2) select{ case s1 := <-output1: print case s2:= <-output2: print }
select 會一直阻塞,除非某個case準備就緒。string
經過select中的case能夠避免信道死鎖,由於case表明有沒有就緒。it
若是一個select沒有任何case,會一直阻塞,致使死鎖。select
WaitGroup用於等待一批Go協程執行結束,程序控制會一直阻塞,直到這些協程所有執行完畢纔會終止。
func process(I int, wg *sync.WaitGroup){ // do something wg.Done() // 讓計數器減一 } func main(){ no := 3 var wg sync.WaitGroup for I := 0; I < no; I++{ wg.Add(1) // 循環3次計數器變成3 go process(I, &wg) // 傳遞地址很重要,若是不傳遞地址,每一個協程都會獲得一個WaitGroup的值拷貝,這樣就不能經過一個計數器控制協做了 } wg.Wait() // 等待主線程變成0 }
WaitGroup使用計數器來工做。調用WaitGroup的Add並傳遞一個int,作累加,減小可調用Done方法。 Wait()方法會阻塞調用WaitGroup的協程,直到計數器爲0後纔會中止阻塞。