常常会看到如下了代码:函数
1 |
package main |
主线程为了等待goroutine都运行完毕,不得不在程序的末尾使用time.Sleep()
来睡眠一段时间,等待其余线程充分运行。对于简单的代码,100个for循环能够在1秒以内运行完毕,time.Sleep()
也能够达到想要的效果。工具
可是对于实际生活的大多数场景来讲,1秒是不够的,而且大部分时候咱们都没法预知for循环内代码运行时间的长短。这时候就不能使用time.Sleep()
来完成等待操做了。ui
能够考虑使用管道来完成上述操做:spa
1 |
func main() { |
首先能够确定的是使用管道是能达到咱们的目的的,并且不但能达到目的,还能十分完美的达到目的。线程
可是管道在这里显得有些大材小用,由于它被设计出来不单单只是在这里用做简单的同步处理,在这里使用管道其实是不合适的。并且假设咱们有一万、十万甚至更多的for循环,也要申请一样数量大小的管道出来,对内存也是不小的开销。设计
对于这种状况,go语言中有一个其余的工具sync.WaitGroup
能更加方便的帮助咱们达到这个目的。指针
WaitGroup
对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait()
用来控制计数器的数量。Add(n)
把计数器设置为n
,Done()
每次把计数器-1
,wait()
会阻塞代码的运行,直到计数器地值减为0。code
使用WaitGroup
将上述代码能够修改成:对象
1 |
func main() { |
这里首先把wg
计数设置为100, 每一个for循环运行完毕都把计数器减一,主函数中使用Wait()
一直阻塞,直到wg为零——也就是全部的100个for循环都运行完毕。相对于使用管道来讲,WaitGroup
轻巧了许多。进程
咱们不能使用Add()
给wg
设置一个负值,不然代码将会报错:
1 |
panic: sync: negative WaitGroup counter |
一样使用Done()
也要特别注意不要把计数器设置成负数了。
WaitGroup对象不是一个引用类型,在经过函数传值的时候须要使用地址:
1 |
func main() { |