sync全稱是synchronization,意思是同步。
WaitGroup同步等待組是有一組goroutine要等待執行,而當前的goroutine需要等待這一組goroutine都執行完才能執行。
下面是WaitGroup的定義:
type WaitGroup struct {
//
}
每個WaitGroup中都有一個計數器counter記錄要等待執行gorouting的數量,可以通過Add這個方法來設定同步等待組中等待goroutine的個數。每個goroutine都會執行,執行完之後都會呼叫done方法表示把計數器的值-1,與此同時,使用wait方法阻塞,直到所goroutine都執行完畢。func (wg *WaitGroup) Add(delta int)
- 如果計數器的值為0,那麼等待過程中被阻塞的goroutine都會被釋放
- 如果計數器得知為負,那麼就會引發panic
那麼具體什麼情況下用,怎麼使用呢?
下面舉個例子:
package main
import "fmt"
func main() {
//waitGroup
go fun1()
go fun2()
}
func fun1() {
for i := 1; i < 10; i++ {
fmt.Println("print A in fun1", i)
}
}
func fun2() {
for i := 0; i < 10; i++ {
fmt.Println("\t fun2 print: ", i)
}
}
這樣最後什麼都沒有列印,因為主goroutine在fun1 fun2這兩個goroutine執行之前結束了。這時候就可以用WaitGroup了。
package main
import (
"fmt"
"sync"
)
//建立同步等待組
var wg sync.WaitGroup
func main() {
//waitGroup
wg.Add(2) //設定計數器為2(goroutine的個數)
go fun1()
go fun2()
fmt.Println("main 進入阻塞狀態, 需要等待wg的goroutine結束")
wg.Wait() //表示main goroutine進入阻塞
fmt.Println("計數器歸零 停止阻塞")
}
func fun1() {
defer wg.Done() //計數器-1
for i := 1; i < 10; i++ {
fmt.Println("print A in fun1", i)
}
}
func fun2() {
defer wg.Done() //計數器-1
for i := 0; i < 10; i++ {
fmt.Println("\t fun2 print: ", i)
}
}
結果如下:
main 進入阻塞狀態, 需要等待wg的goroutine結束
print A in fun1 1
print A in fun1 2
fun2 print: 0
fun2 print: 1
fun2 print: 2
fun2 print: 3
fun2 print: 4
print A in fun1 3
print A in fun1 4
print A in fun1 5
print A in fun1 6
print A in fun1 7
print A in fun1 8
print A in fun1 9
fun2 print: 5
fun2 print: 6
fun2 print: 7
fun2 print: 8
fun2 print: 9
計數器歸零 停止阻塞
結果第一行,說明兩個goroutine已經都啟動了,然後交替使用CPU的時間片。
另外 如果函式執行完畢的時候,計數器的值仍然大於0,會引起deadlock。
另外 Go語言並不推薦上述寫法,更加推薦使用chanel。
資料參考:bilibili