Golang的sync WaitGroup

goroutine会在主线程return之后强制退出,所以为了等待goroutine都运行完毕,不得不在程序的末尾使用time.Sleep()来睡眠一段时间,等待其他的线程充分运行,对于简单的代码,timeSleep()也可以达到想要的结果。hhh,对于实际的应用场景来说,n秒是不够的,大部分场景的运行时间无法预知,所以这时候就需要使用channel来处理这类场景了。
func main() {
c := make(chan bool, 100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
c <- true
}(i)
}
for i := 0; i < 100; i++ {
<-c
}
}
上面使用channel,实际上也不是很合适,如果我们有十万的的循环,也要申请同样数量的大小管道出来,对内存也是不小的开销。对于这种情况,go语言中有一个其他的工具,sync.WaitGroup 能更加方便的帮助我们达到这个目的。
WaitGroup对象内部有一个计数器,最初从0开始,它有三个方法,Add(),Done(),Wait()用来控制计数器的数量。Add(n)把计数器设置为n,Done()每次把计数器-1,wait()会阻塞代码的运行,直到计数器地值减为0。
func main() {
wg := sync.WaitGroup{}
wg.Add(100) //计数器设置为100
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
wg.Done() //每次都把计数器-1
}(i)
}
wg.Wait() //阻塞代码运行,直到计数器的值减为0
}
ps :注意计数器不能为负值,如果为负报错:panic: sync: negative WaitGroup counter
WaitGroup 对象不是一个引用类型,在通过函数传值的时候需要使用地址:
func main(){
wg:= sync.WaitGroup{}
wg.Add(100)
for i:=0;i < 100; i++ {
go f(i,&wg)
}
wg.Wait()
}
//一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup){
fmt.Println(i)
wg.Done()
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注