失常状况下,新激活的goroutine的完结过程是不可管制的,惟一能够保障终止goroutine的行为是main goroutine的终止。
也就是说,咱们并不知道哪个goroutine什么时候完结。
但很多状况下,咱们正须要晓得goroutine是否实现。这须要借助sync包的WaitGroup来实现。
WatiGroup是sync包中的一个struct类型,用来收集须要期待执行实现的goroutine。上面是它的定义:
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个办法:
Add():每次激活想要被期待实现的goroutine之前,先调用Add(),用来设置或增加要期待实现的goroutine数量
例如Add(2)或者两次调用Add(1)都会设置期待计数器的值为2,示意要期待2个goroutine实现
Done():每次须要期待的goroutine在真正实现之前,应该调用该办法来人为示意goroutine实现了,该办法会对期待计数器减1
Wait():在期待计数器减为0之前,Wait()会始终阻塞以后的goroutine
也就是说,Add()用来减少要期待的goroutine的数量,Done()用来示意goroutine曾经实现了,缩小一次计数器,Wait()用来期待所有须要期待的goroutine实现。
上面是一个示例,通过示例很容易了解。
package mainimport ( "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() // Done()用来示意goroutine曾经实现了,缩小一次计数器}func main (){ no:=3 var wg sync.WaitGroup for i:=0;i<no;i++{ wg.Add(1) go process(i,&wg) } wg.Wait() // Wait()用来期待所有须要期待的goroutine实现。 fmt.Println("All go routines finished executing")}
运行后果
PS D:goLanggithubgolang_projectgolang_projectReptiles> go run .test.go
started Goroutine 2started Goroutine 0started Goroutine 1Goroutine 2 endedGoroutine 0 endedGoroutine 1 endedAll 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()。还有一点须要特地留神的是process()中应用指针类型的*sync.WaitGroup作为参数,这里不能应用值类型的sync.WaitGroup作为参数,因为这意味着每个goroutine都拷贝一份wg,每个goroutine都应用本人的wg。这显然是不合理的,这3个goroutine应该共享一个wg,能力晓得这3个goroutine都实现了。实际上,如果应用值类型的参数,main goroutine将会永恒阻塞而导致产生死锁。