正常狀況下,新激活的goroutine的結束過程是不可控制的,惟一能夠保證終止goroutine的行爲是main goroutine的終止。也就是說,咱們並不知道哪一個goroutine何時結束。函數
但不少狀況下,咱們正須要知道goroutine是否完成。這須要藉助sync包的WaitGroup來實現。指針
WatiGroup是sync包中的一個struct類型,用來收集須要等待執行完成的goroutine。下面是它的定義:code
type WaitGroup struct { // Has unexported fields. } 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. A WaitGroup must not be copied after first use. func (wg *WaitGroup) Add(delta int) func (wg *WaitGroup) Done() func (wg *WaitGroup) Wait()
它有3個方法:it
也就是說,Add()用來增長要等待的goroutine的數量,Done()用來表示goroutine已經完成了,減小一次計數器,Wait()用來等待全部須要等待的goroutine完成。io
下面是一個示例,經過示例很容易理解。import
package main import ( "fmt" "sync" "time" ) func process(i int, wg *sync.WaitGroup) { fmt.Println("started Goroutine ", i) time.Sleep(2 * time.Second) fmt.Printf("Goroutine %d ended\n", i) wg.Done() } func main() { no := 3 var wg sync.WaitGroup for i := 0; i < no; i++ { wg.Add(1) go process(i, &wg) } wg.Wait() fmt.Println("All go routines finished executing") }
上面激活了3個goroutine,每次激活goroutine以前,都先調用Add()方法增長一個須要等待的goroutine計數。每一個goroutine都運行process()函數,這個函數在執行完成時須要調用Done()方法來表示goroutine的結束。激活3個goroutine後,main goroutine會執行到Wait(),因爲每一個激活的goroutine運行的process()都須要睡眠2秒,因此main goroutine在Wait()這裏會阻塞一段時間(大約2秒),當全部goroutine都完成後,等待計數器減爲0,Wait()將再也不阻塞,因而main goroutine得以執行後面的Println()。sed
還有一點須要特別注意的是process()中使用指針類型的*sync.WaitGroup
做爲參數,這裏不能使用值類型的sync.WaitGroup
做爲參數,由於這意味着每一個goroutine都拷貝一份wg,每一個goroutine都使用本身的wg。這顯然是不合理的,這3個goroutine應該共享一個wg,才能知道這3個goroutine都完成了。實際上,若是使用值類型的參數,main goroutine將會永久阻塞而致使產生死鎖。方法