一、前言
waitgroup在golang中,用于线程同步,指等待一个组,等待一个系列执行完成后,才会向下执行,可以解决一个 进程goroutine 等待多个该进程启动的子线程goroutine 都正常运行完成的场景,这个比较常见的场景就是例如 后端 main processer 启动了多个消费者worker干活,还有爬虫并发爬取数据,多线程下载等等,为了保证主进程在所有的子线程完成后再退出,这时就要用上waitgroup
没有使用WaiGroup
package main
import (
"fmt"
"sync"
"time"
)
//waitgroup 将函数分开到其他线程中执行
func main() {
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
time.Sleep(1e9)
go func() {
fmt.Println(i)
time.Sleep(1e9)
wg.Done()
}()
}
//wg.Wait() //等待go中的线程完成之后才退出
fmt.Println("程序结束")
}
执行结果
1
2
3
4
程序结束
i=5这个线程没有输出结果,主程序就结束了
加上wg.Wait()等待所有子线程结束了,主线程才结束
输出结果
1
2
3
4
5
程序结束
当然,我写的子线程有点少,你们可以写多点
总结:
同时我们在使用waitgroup时也要注意一些坑:
1、 Add一个负数
如果计数器的值小于0会直接panic
2、 Add在Wait之后调用
比如一些子协程开头调用Add结束调用Wait,这些 Wait无法阻塞子协程。正确做法是在开启子协程之前先Add特定的值。
3、 未置为0就重用
WaitGroup可以完成一次编排任务,计数值降为0后可以继续被其他任务所用,但是不要在还没使用完的时候就用于其他任务,这样由于带着计数值,很可能出问题。
4、 复制waitgroup
WaitGroup有nocopy字段,不能被复制。也意味着WaitGroup不能作为函数的参数
waitgroup使用总结
WaitGroup是Golang应用开发过程中经常使用的并发控制技术,学习golang是我们必须要掌握和理解的机制之一,建议有时间了大家再进一步的研究一下WaitGroup的底层实现逻辑。