Go 併發(二)

Go Mutex

經過Mutex和信道處理競態條件。併發

臨界區

當程序併發運行時,多個協程不該該同時訪問那些修改共享資源的代碼,這些修改共享資源的代碼稱爲臨界區。線程

Go中經過Mutex能夠避免同時訪問臨界區,從而避免了競態條件。code

Mutex

Mutex提供了一種鎖機制,能夠確保某個時刻只有一個協程在臨界區運行,防止出現競態條件。server

Mutex中定義了兩個方法:Lock和Unlock。 Lock和Unlock之間的代碼只能由一個協程執行,避免了競態條件。協程

mutex.Lock()
x = x+1
mutex.Unlock()

經過Mutex避免競態

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()
}

Go select

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

Go WaitGroup

WaitGroup

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後纔會中止阻塞。

相關文章
相關標籤/搜索