Go goroutine同步
來自: http://andrewliu.in/2016/04/08/Go-goroutine同步/
本博客采用創作共用版權協議, 要求署名、非商業用途和保持一致. 轉載本博客文章必須也遵循 署名-非商業用途-保持一致 的創作共用協議.
出現問題場景: 一個函數run()中包含多個goroutine函數并發, 這些goroutine函數會生成中間文件, 被run()函數運行結束后的check()函數檢查. 當goroutine并發時, 并不會阻塞run()的上下文, 可能導致的情況為run()函數執行完畢( 但其中的goroutine并發函數沒有執行完畢 ), 導致check()函數執行失敗.
所以我們需要一種操作, 直到當前所有goroutine沒有執行完畢, 才進行下一步操作
所以需要 goroutine同步 , go提供了 sync包 和 channel機制 來解決goroutine之間的同步問題
sync.WaitGroup
A WaitGroup waits foracollectionofgoroutinestofinish. The main goroutine calls Addtosetthenumberofgoroutinestowaitfor. Theneachofthegoroutines runsandcalls Done when finished. Atthesametime, Wait can be usedtoblockuntilall goroutines have finished.-- 出自官方文檔
大概意思是: WaitGroup 等待一組goroutinue執行完畢. 主goroutinue調用 Add 設置等待的goroutinue數量. 每個goroutinue應該在執行結束時調用 Done . Wait 會阻塞知道所有goroutinue執行完畢.
WaitGroup 的用于某個地方需要創建多個goroutine,并且一定要等它們都執行完畢后再繼續執行接下來的操作.
可以把 WaitGroup 看作一個類似任務隊列的結構. Add想隊列增加任務, Done完成任務, Wait在隊列不空的時候阻塞在哪里.
// 官方文檔中的example packagemainimport( "fmt" "sync" "net/http" )
funcmain() { varwg sync.WaitGroup// 聲明一個WaitGroup變量 varurls = []string{ "channel
channel同樣可以用來同步goroutinue
channel四種操作
// make創建chennel, 第一個參數為channel的類型, 第二個參數為channel緩沖區的大小, 為0或者不傳入該參數則表示沒有緩沖區 exampleChannel := make(chanint,100)// 放入數據到channel (channel <- data) exampleChannel <-1
// 取出數據 (<-channel) number := <-exampleChannel
// 關閉channel (通過close()函數) close(exampleChannel) </pre>
channel是一種 阻塞管道 , 是自動阻塞的. 如果 channel 滿了, 對channel放入數據的操作就會阻塞, 直到有某個routine從channel中取出數據, 這個放入數據的操作才會執行. 相反同理, 如果管道是空的, 一個從channel取出數據的操作就會阻塞,直到某個routine向這個channel中放入數據, 這個取出數據的操作才會執行(原理非常類似阻塞型socket的讀寫緩沖區)
// 上面的樣例代碼使用chan同步的方式來重寫 packagemainimport( "fmt" "net/http" )
funcmain() { varurls = []string{ "當任務的數量不固定
packagemainimport( "fmt" )
functest_chan(groutineChanchanint, feedbackChanchanstring) { deferfunc() { <-groutineChan feedbackChan <- "finish" }()
// do some process // ... }
funcmain() { var( goroutineChan chanint=make(chanint,20) feedbackChan chanstring=make(chanstring,10000) counter int finish int ) fori :=0; i <1000; i++ { goroutineChan <-1 counter++ gotest_chan(goroutineChan, feedbackChan) }
for{ msg := <-feedbackChan // 從channel取出字符串 ifmsg =="finish"{ finish++ // 沒完成一個完成計數器加一 } iffinish == counter {//當完全計數器等于計數器表示所有的goroutine完成 break } } fmt.Printf("Finish..\n") } </pre>
參考鏈接