Golang 程式中使用 sync.WaitGroup 同步多個 Goroutine
編寫併發的程式時,經常會遇到需要同步多個協程/執行緒的狀態/資料的問題。在 Golang 程式中同步多個 Goroutine 的最簡單的辦法就是使用 sync.WaitGroup。
下面是官網的介紹:
A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.
從中我們可以提取出幾點關鍵資訊:
- WaitGroup 可以用於等待一系列的 Goroutine 完成任務;
- Add 方法須在 main goroutine 中呼叫;
- Done 方法須在其它新建的 goroutine 中呼叫;
- Wait 方法可以阻塞等待直至其它 goroutine 完成;
Talk is cheap. Show me the code.
package main import ( "fmt" "sync" "time" ) func TaskA(wg *sync.WaitGroup) { defer wg.Done() time.Sleep(1 * time.Second) fmt.Println("task a done...") } func TaskB(wg *sync.WaitGroup) { defer wg.Done() time.Sleep(3 * time.Second) fmt.Println("task b done...") } func TaskC(wg *sync.WaitGroup) { defer wg.Done() time.Sleep(5 * time.Second) fmt.Println("task c done...") } func main() { var wg sync.WaitGroup //開啟一個 goroutine 前,在 main goroutine 中呼叫 wg.Add //為什麼強調一定要在 main goroutine 中呼叫 wg.Add,而不能在 //新建的 goroutine 中呼叫呢?我的理解是如果延遲到新建的 //goroutine 中呼叫 wg.Add 就有可能造成 wg.Wait 先執行。若是 //如此,必定不能達到如期的效果。 wg.Add(1) //傳遞給 goroutine 的 WaitGroup 變數必須為指標型別,因為在 //Golang 中所有的函式引數都是值傳遞,也就是在函式體內會複製一 //份引數的副本。如果不使用指標型別就無法引用到同一個 WaitGroup //變數,便也不能依賴 WaitGroup 來實現同步了。 go TaskA(&wg) wg.Add(1) go TaskC(&wg) wg.Add(1) go TaskB(&wg) //阻塞等待直至所有其它的 goroutine 都已執行完畢 wg.Wait() fmt.Println("all the tasks done...") }