Go語言中除了可使用通道(channel)和互斥鎖進行兩個併發程序間的同步外,還可使用等待組進行多個任務的同步,等待組能夠保證在併發環境中完成指定數量的任務git
在 sync.WaitGroup(等待組)類型中,每一個 sync.WaitGroup 值在內部維護着一個計數,此計數的初始默認值爲零。golang
等待組有下面幾個方法可用,以下所示。併發
對於一個可尋址的 sync.WaitGroup 值 wg:函數
等待組內部擁有一個計數器,計數器的值能夠經過方法調用實現計數器的增長和減小。當咱們添加了 N 個併發任務進行工做時,就將等待組的計數器值增長 N。每一個任務完成時,這個值減 1。同時,在另一個 goroutine 中等待這個等待組的計數器值爲 0 時,表示全部任務已經完成。oop
什麼意思?咱們先來回憶一下以前咱們爲了保證子 go 程運行完畢,主 go 程是怎麼作的:網站
package main import ( "fmt" "time" ) func main() { go func() { fmt.Println("Goroutine 1") }() go func() { fmt.Println("Goroutine 2") }() time.Sleep(time.Second) // 睡眠 1 秒,等待上面兩個子 go 程結束 }
咱們爲了讓子 go 程能夠順序的執行完,在主 go 程中加入了等待。咱們知道,這不是一個很好的解決方案,能夠用 channel 來實現同步:code
package main import ( "fmt" ) func main() { ch := make(chan struct{}) count := 2 // count 表示活動的 go 程個數 go func() { fmt.Println("Goroutine 1") ch <- struct{}{} // go 程結束,發出信號 }() go func() { fmt.Println("Goroutine 2") ch <- struct{}{} // go 程結束,發出信號 }() for range ch { // 每次從 ch 中接收數據,代表一個活動的 go 程結束 count-- // 當全部活動的 go 程都結束時,關閉 channel if count == 0 { close(ch) } } }
上面的解決方案是雖然已經比較好了,可是 Go 提供了更簡單的方法:使用 sync.WaitGroup
。協程
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(2) // 由於有兩個動做,因此增長 2 個計數 go func() { fmt.Println("Goroutine 1") wg.Done() // 操做完成,減小一個計數 }() go func() { fmt.Println("Goroutine 2") wg.Done() // 操做完成,減小一個計數 }() wg.Wait() // 等待,直到計數爲0 }
可見用 sync.WaitGroup
是最簡單的方式。對象
強調一下:文檔
Add()
或者 Done()
給 wg 設置一個負值,不然代碼將會報錯。官方文檔看這裏:https://golang.org/pkg/sync/#WaitGroup
一、寫代碼實現兩個 goroutine,其中一個產生隨機數並寫入到 go channel 中,另一個從 channel 中讀取數字並打印到標準輸出。最終輸出五個隨機數。
package main import ( "fmt" "math/rand" "sync" ) func main() { ch := make(chan int) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for i := 0; i < 5; i++ { ch <- rand.Int() } close(ch) }() wg.Add(1) go func() { defer wg.Done() for num := range ch { fmt.Println("num = ", num) } }() wg.Wait() }
歡迎訪問個人我的網站:
李培冠博客:lpgit.com