Go goroutine同步

CarWelker 8年前發布 | 10K 次閱讀 Goroutine Google Go/Golang開發

來自: 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
packagemain

import( "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同步的方式來重寫
packagemain

import( "fmt" "net/http" )

funcmain() { varurls = []string{ "當任務的數量不固定

packagemain

import( "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>

參考鏈接

 本文由用戶 CarWelker 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!