话不多说,看代码:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i:=0;i<20;i++{
wg.Add(1)
go func(x int) {
defer wg.Done()
fmt.Print(" ",x)
}(i)
}
fmt.Printf("\n%#v\n",wg)
wg.Wait()
fmt.Println("\nThe End!")
}
执行两次,分别看一下结果:
我们看到每次“The End”都可以正确输出,也就是所有goroutine都执行完之后才会执行我们最后一句代码。
下面我们就来分析一下sync.WaitGroup的原理。
sync.WaitGroup定义如下:
type WaitGroup struct{
noCopy noCopy
state1 [12] byte
sema uint12
}
state1字段是一个计数器,每当有一个goroutine运行时,就调用wg.Add()方法给计数器加1,当一个goroutine完成时,调用wg.Done()方法给计数器减1,wg.Wait()等待计数器变为0。
这里注意add和done方法都是在主goroutine中执行的,而Done方法是在启动的goroutine中执行的。