Golang sync.WaitGroup 简介与用法
1.简介
sync.WaitGroup 用于阻塞等待一组 Go 程的结束。主 Go 程调用 Add() 来设置等待的 Go 程数,然后该组中的每个 Go 程都需要在运行结束时调用 Done(), 递减 WaitGroup 的 Go 程计数器 counter。当 counter 变为 0 时,主 Go 程被唤醒继续执行。
type WaitGroup struct {// contains filtered or unexported fields
}// 设置需要等待的 Go 程数量
func (wg *WaitGroup) Add(delta int)// Go 程计数器减 1
func (wg *WaitGroup) Done()// 阻塞等待所有 Go 程结束(等待 Go 程计数器变为 0)
func (wg *WaitGroup) Wait()
WaitGroup 有三个方法,其中 Done() 调用了 Add(-1)。标准用法:
(1)启动 Go 程时调用 Add();
(2)在 Go 程结束时调用 Done();
(3)最后调用 Wait()。
2.使用示例
package mainimport ("fmt""sync" "time"
)func foo1() {defer wg.Done()fmt.Println("exit foo1")
}func foo2() {defer wg.Done()fmt.Println("exit foo2")
}func main() {fmt.Println("entry main")var wg sync.WaitGroupwg.Add(2)go foo1()go foo2()fmt.Println("wg.Wait()")wg.Wait()fmt.Println("exit main")
}
编译运行输出:
entry main
wg.Wait()
exit foo2
exit foo1
exit main
注意: 多次执行输出结果中 “exit foo2” 和 “exit foo1” 的先后顺序是不定的,因为多协程并发执行的顺序是随机的。
3.错误示例
如果使用过程中通过 Add() 添加的 Go 程数与调用 Done() 的次数不符,即 sync.WaitGroup 的 Go 程计数器等所有子 Go 程结束后不为 0,则会引发 panic。
3.1 Done() 过多
func main() {fmt.Println("entry main")var wg sync.WaitGroupwg.Done()fmt.Println("wg.Wait()")wg.Wait()fmt.Println("exit main")
}
编译运行输出:
entry main
panic: sync: negative WaitGroup countergoroutine 1 [running]:
sync.(*WaitGroup).Add(0xc4200140d0, 0xffffffffffffffff)/usr/lib/golang/src/sync/waitgroup.go:75 +0x134
sync.(*WaitGroup).Done(0xc4200140d0)/usr/lib/golang/src/sync/waitgroup.go:100 +0x34
main.main()/data/goTest/src/waitgroup/main.go:34 +0x8e
可见,当 Go 程计数器变为负数时,将引发 panic。
3.2 Done() 过少
注释掉 foo2() 中的 defer wg.Done()
,使得 Go 程结束时不减少 sync.WaitGroup 的 Go 程计数器。
func foo2() {//defer wg.Done()fmt.Println("exit foo2")
}
编译运行输出:
entry main
wg.Wait()
exit foo1
exit foo2
fatal error: all goroutines are asleep - deadlock!goroutine 1 [semacquire]:
sync.runtime_Semacquire(0x54aa7c)/usr/lib/golang/src/runtime/sema.go:56 +0x39
sync.(*WaitGroup).Wait(0x54aa70)/usr/lib/golang/src/sync/waitgroup.go:131 +0x72
main.main()/data/goTest/src/waitgroup/main.go:33 +0x10e
这个错误表明,在最后一个活动线程 foo2 退出的时候,Go 检测到当前没有还在运行的 Go 程,但主 Go 程仍在等待,发生了死锁现象,于是引发 panic,这是 Go 的一种自我保护机制。
4.errgroup
鉴于使用 sync.WaitGroup 容易出错,Go 官方包 errgroup 进一步对 sync.WaitGroup 进行了封装,不再需要 Add 和 Done,用起来更加简单方便。详见 golang.org/x/sync/errgroup。
package mainimport ("fmt""sync""golang.org/x/sync/errgroup"
)func foo1() {fmt.Println("exit foo1")
}func foo2() {fmt.Println("exit foo2")
}func main() {fmt.Println("entry main")var g errgroup.Groupg.Go(func() error {foo1()return nil})g.Go(func() error {foo2()return nil})fmt.Println("g.Wait()")g.Wait()fmt.Println("exit main")
}
运行输出:
entry main
wg.Wait()
exit foo2
exit foo1
exit main
参考文献
[1] Golang
[2] golang语言异步通信之WaitGroup
Golang sync.WaitGroup 简介与用法相关推荐
- Golang sync.Pool 简介与用法
文章目录 1.简介 2.应用 2.1 标准库的应用 2.2 复用 bytes.Buffer 参考文章 1.简介 Pool 是可伸缩.并发安全的临时对象池,用来存放已经分配但暂时不用的临时对象,通过对象 ...
- Golang sync.Cond 简介与用法
文章目录 1.简介 2.使用场景 3.原理 4.使用示例 5.注意事项 参考文章 1.简介 sync.Cond 是基于互斥锁/读写锁实现的条件变量,用来协调想要访问共享资源的那些 Goroutine. ...
- Golang sync.Map 简介与用法
Golang 中的 map 在并发情况下,只读是线程安全的,并发读写线程不安全.为了解决这个问题,Golang 提供了语言层级的并发读写安全的 sync.Map. type Map struct {/ ...
- Golang sync.Once 简介与用法
文章目录 1.简介 2.延迟初始化 参考文献 1.简介 sync.Once用来保证函数只执行一次.要达到这个效果,需要做到两点: (1)计数器,统计函数执行次数: (2)线程安全,保障在多 Go 程的 ...
- golang goroutine 协程同步 sync.WaitGroup 简介
介绍 经常会看到以下了代码: package mainimport ("fmt""time" )func main(){for i := 0; i < 1 ...
- golang sync WaitGroup
2019独角兽企业重金招聘Python工程师标准>>> 简介 它能够一直等到所有的goroutine执行完成,并且阻塞主线程的执行,直到所有的goroutine执行完成. WaitG ...
- Go sync.WaitGroup的用法
介绍 经常会看到以下了代码: package mainimport ("fmt""time" )func main(){for i := 0; i < 1 ...
- golang中的sync.WaitGroup
golang中的sync.WaitGroup Posted on 2015/04/09刚才看golang的sync的包,看见一个很有用的功能.就是WaitGroup. 先说说WaitGroup的用途: ...
- Golang gorouting 并发控制 sync.WaitGroup 介绍与使用
WaitGroup简称同步组,用于等待goroutines结束的. 官方文档: type WaitGroupA WaitGroup waits for a collection of goroutin ...
最新文章
- 认识计算机ppt课件游戏,认识计算机)ppt课件
- 01_字符串处理-----04_在文本中应用ZIpf定律
- 深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)
- Spark在集群中的安装
- 基于认证的代理平台搭建配置squid-20130730
- Java中ArrayList最大容量为什么是Integer.MAX_VALUE-8?
- ffmpeg 源码学习之seek play
- 利用赫夫曼编码进行数据解压
- cocos2dx libevent简介和使用
- 第 3 章 镜像 - 018 - 镜像命名的最佳实践
- 优酷直播节目“冠军体育课”第二季收官 共吸引近百万用户观看互动
- Ubuntu下远程访问MySQL数据库
- 51单片机 模块化编程
- AGND为模拟地,DGND为数字地
- Max Core Frequency 异常显示为-1.80GHz -- Intel-Extreme-Tuning-Utility-Intel-XTU (英特尔 XTU)
- cad找形心插件 lisp_晓东CAD家园-论坛-A/VLISP-[LISP程序]:求形心-谁有求形心的LISP.帮帮忙。时在是太累啦。 - Powered by Discuz!...
- 将高分三号中的SAR图可视化处理
- addr2line来定位问题
- 【托业】【新托业TOEIC新题型真题】学习笔记5-题库二-P7
- 【唐老狮】Unity和UE4两大游戏引擎,你该如何选择?