共计 2036 个字符,预计需要花费 6 分钟才能阅读完成。
失常状况下,新激活的 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 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() // 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 2
started Goroutine 0
started Goroutine 1
Goroutine 2 ended
Goroutine 0 ended
Goroutine 1 ended
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()。还有一点须要特地留神的是 process()中应用指针类型的 *sync.WaitGroup 作为参数,这里不能应用值类型的 sync.WaitGroup 作为参数,因为这意味着每个 goroutine 都拷贝一份 wg,每个 goroutine 都应用本人的 wg。这显然是不合理的,这 3 个 goroutine 应该共享一个 wg,能力晓得这 3 个 goroutine 都实现了。实际上,如果应用值类型的参数,main goroutine 将会永恒阻塞而导致产生死锁。