当前位置:网站首页>Golang sync.WaitGroup
Golang sync.WaitGroup
2022-08-03 12:47:00 【云满笔记】
1. Golang sync.WaitGroup
1.1. 基础知识
这个是通过通道, 来控制 goroutine 协程结束的示例:
func coordinateWithChan() {
sign := make(chan struct{
}, 2) num := int32(0) fmt.Printf("The number: %d [with chan struct{}]\n", num) max := int32(10) go addNum(&num, 1, max, func() {
sign <- struct{
}{
} }) go addNum(&num, 2, max, func() {
sign <- struct{
}{
} }) <-sign <-sign}
上一节我们学习过, sign 通道读取数据时, 如果命中"有缓冲 channel + 缓冲为空"的情况, 会阻塞, 只有两个 go 协程全部执行完毕, 往 sign 塞数据后, 程序才会退出, 但是这种方式非常繁琐。在这种应用场景下, 我们可以选用另外一个同步工具 sync.WaitGroup(以下简称 WaitGroup 类型), 它比通道更加适合实现这种一对多的 goroutine 协作流程。WaitGroup 类型是开箱即用的, 也是并发安全的, 它拥有三个指针方法: Add、Done 和 Wait, 你可以想象该类型中有一个计数器, 它的默认值是 0, 我们可以通过调用该类型值的 Add 方法来增加, 或者减少这个计数器的值, 代码升级如下:
func coordinateWithWaitGroup() {
var wg sync.WaitGroup wg.Add(2) // 计数器加 2 num := int32(0) fmt.Printf("The number: %d [with sync.WaitGroup]\n", num) max := int32(10) go addNum(&num, 3, max, wg.Done) // 计数器减 1 go addNum(&num, 4, max, wg.Done) // 计数器减 1 wg.Wait() // 会阻塞, 直到计数器值为 0, 然后就会被唤醒}
Add 会增加计数器的值, Done 会减少计数器的值, Wait 会一直阻塞, 直到计数器的值重新回归为 0, 然后才会被唤醒, 继续往后面执行。
1.2. 常见的坑
如果使用不当, 容易抛出 Panic, 我就把相关知识点列出来:
- 坑 1(计数器为负数): sync.WaitGroup 类型值中计数器的值如果小于 0, 会直接抛出 Panic。
- 坑 2(同时调用 Add 和 Wait): 如果我们对它的 Add 方法的首次调用, 与对它的 Wait 方法的调用是同时发起的, 比如, 在同时启用的两个 goroutine 中, 分别调用这两个方法, 那么就有可能会让这里的 Add 方法抛出一个 panic。
- 坑 3(跨越计数周期): 如果在一个此类值的 Wait 方法被执行期间, 跨越了两个计数周期, 那么就会引发一个 panic。
对于坑 1, 当调用 Add 方法, 传入一个负数的时候可能会出现, 所以我们使用 WaitGroup 时, 需要保证计数一直大于 0。对于坑 2, 需要说明一点, 虽然 WaitGroup 值本身并不需要初始化, 但是尽早地增加其计数器的值, 还是非常有必要的。对于坑 3, 我们需要先了解 WaitGroup 的计数周期:
计数周期: WaitGroup 中计数器值由 0 变为了某个正整数, 而后又经过一系列的变化, 最终由某个正整数又变回了 0。也就是说, 只要计数器的值始于 0 又归为 0, 就可以被视为一个计数周期。在一个此类值的生命周期中, 它可以经历任意多个计数周期。但是, 只有在它走完当前的计数周期之后, 才能够开始下一个计数周期。那坑 3 什么情况会出现呢? 场景如下: 当前的 goroutine 因调用 Wait 方法被阻塞的时候, 另一个 goroutine 调用了该值的 Done 方法, 并使其计数器的值变为了 0, 这会唤醒当前的 goroutine, 并使它试图继续执行 Wait 方法中其余的代码。但在这时, 又有一个 goroutine 调用了它的 Add 方法, 并让其计数器的值又从 0 变为了某个正整数。此时, 这里的 Wait 方法就会立即抛出一个 panic。根据坑 2 和坑 3, 总结如下: 不要把增加其计数器值的操作和调用其 Wait 方法的代码, 放在不同的 goroutine 中执行。换句话说, 要杜绝对同一个 WaitGroup 值的两种操作的并发执行, 标准方式应该为"先统一 Add, 再并发 Done, 最后 Wait"。
1.3. 并发实例: Push
对于上一章的并发示例, 当时提了一个问题: 每消费一条 Channel 数据, 需要记录 Push 发送成功, 但是一条 Channel 数据包含 2-3 个 Push 内容 (IOS/Android/PC), 程序记录 Push 成功前, 如何保证这 2-3 个 Push 都发送完毕了呢? 根据"先统一 Add, 再并发 Done, 最后 Wait"原则, 看下面代码:
var ( wg sync.WaitGroup succs []*NotifyMessage fails []*NotifyMessage)for _, message := range t.PushMessages {
wg.Add(1) // 计数加 1 go func(message mipush.PushMessage) { defer func() { wg.Done() // 计数减 1 }() // 发送 IOS/Android/PC 等渠道的 Push // 代码省略。.. }(message)}wg.Wait() // 阻塞, 直到计数器值为 0, 然后就会被唤醒// 数据统计 SendNotify(t.ID, t.TotalPage, t.TaskPage, t.AppType, t.AppLocal, fails, succs)
1.4. 总结
WaitGroup 是开箱即用和并发安全的, 可以通过它很方便地实现一对多 goroutine 协作流程, 即: 一个分发子任务的 goroutine, 和多个执行子任务的 goroutine, 共同来完成一个较大的任务。在使用 WaitGroup 值的时候, 我们一定要注意, 千万不要让其中的计数器的值小于 0, 否则就会引发 panic。另外, 我们最好用"先统一 Add, 再并发 Done, 最后 Wait"这种标准方式, 来使用 WaitGroup 值, 尤其不要在调用 Wait 方法的同时, 并发地通过调用 Add 方法去增加其计数器的值, 因为这也有可能引发 panic。
边栏推荐
- 什么是分布式锁?几种分布式锁分别是怎么实现的?
- Blog records life
- How can I get a city's year-round weather data for free?Precipitation, temperature, humidity, solar radiation, etc.
- php microtime 封装工具类,计算接口运行时间(打断点)
- 超多精美礼品等你来拿!2022年中国混沌工程调查启动
- Jmeter use
- 软件测试自学还是报班好?
- Classes and objects (upper)
- Basic principle of the bulk of the animation and shape the An animation tip point
- 利用pgsql插件PostGIS 实现地理坐标系数据转换
猜你喜欢

基于php网上零食商店管理系统获取(php毕业设计)

汉源高科G8032标准ERPS环网交换机千兆4光10电工业以太网交换机环网+WEB管理+SNMP划VLAN

无监督学习KMeans学习笔记和实例

类型转换、常用运算符

Image fusion SDDGAN article learning

An动画优化之补间形状与传统补间的优化

The components of the basis of An animation movie clip animation between traditional filling

实数取整写入文件(C语言文件篇)

Sogou news - dataset

An工具介绍之骨骼工具
随机推荐
An工具介绍之3D工具
云计算服务主要安全风险及应对措施初探
An introduction to 3D tools
层次分析法
字节最爱问的智力题,你会几道?
Using the Work Queue Manager (4)
From the physical level of the device to the circuit level
An动画基础之元件的影片剪辑动画与传统补间
Redis连接池工具类
【蓝桥杯选拔赛真题48】Scratch跳舞机游戏 少儿编程scratch蓝桥杯选拔赛真题讲解
ECCV 2022|通往数据高效的Transformer目标检测器
类和对象(中下)
(通过页面)阿里云云效上传jar
leetcode16 Sum of the closest three numbers (sort + double pointer)
AMS simulation
【Verilog】HDLBits题解——Verification: Reading Simulations
业界新标杆!阿里开源自研高并发编程核心笔记(2022最新版)
IDEA的模板(Templates)
第十五章 源代码文件 REST API 简介
An动画优化之传统引导层动画