当前位置:网站首页>Golang sync.WaitGroup
Golang sync.WaitGroup
2022-08-03 13:16:00 【Cloud full of notes】
1. Golang sync.WaitGroup
1.1. 基础知识
This is through the channel, 来控制 goroutine Example of coroutine ending:
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}
We learned in the previous section, sign When the channel reads data, 如果命中"有缓冲 channel + 缓冲为空"的情况, 会阻塞, 只有两个 go The coroutine is all executed, 往 sign After plugging the data, 程序才会退出, 但是这种方式非常繁琐.在这种应用场景下, 我们可以选用另外一个同步工具 sync.WaitGroup(以下简称 WaitGroup 类型), 它比通道更加适合实现这种一对多的 goroutine 协作流程.WaitGroup 类型是开箱即用的, 也是并发安全的, It has three pointer methods: Add、Done 和 Wait, 你可以想象该类型中有一个计数器, 它的默认值是 0, 我们可以通过调用该类型值的 Add 方法来增加, 或者减少这个计数器的值, The code upgrade is as follows:
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, Then it will wake up}
Add 会增加计数器的值, Done will decrement the value of the counter, Wait 会一直阻塞, until the value of the counter returns to 0, and then wake up, Continue to execute backwards.
1.2. 常见的坑
如果使用不当, 容易抛出 Panic, I will list the relevant knowledge points:
- 坑 1(The counter is negative): sync.WaitGroup The value of the counter in type value if less than 0, 会直接抛出 Panic.
- 坑 2(同时调用 Add 和 Wait): 如果我们对它的 Add 方法的首次调用, 与对它的 Wait 方法的调用是同时发起的, 比如, 在同时启用的两个 goroutine 中, 分别调用这两个方法, 那么就有可能会让这里的 Add 方法抛出一个 panic.
- 坑 3(spanning count cycles): 如果在一个此类值的 Wait 方法被执行期间, 跨越了两个计数周期, 那么就会引发一个 panic.
对于坑 1, 当调用 Add 方法, May appear when a negative number is passed in, 所以我们使用 WaitGroup 时, Need to ensure that the count is always greater than 0.对于坑 2, 需要说明一点, 虽然 WaitGroup 值本身并不需要初始化, 但是尽早地增加其计数器的值, 还是非常有必要的.对于坑 3, 我们需要先了解 WaitGroup 的计数周期:
计数周期: WaitGroup The medium counter value is given by 0 变为了某个正整数, 而后又经过一系列的变化, 最终由某个正整数又变回了 0.也就是说, 只要计数器的值始于 0 又归为 0, 就可以被视为一个计数周期.在一个此类值的生命周期中, 它可以经历任意多个计数周期.但是, 只有在它走完当前的计数周期之后, 才能够开始下一个计数周期.that pit 3 What will happen? 场景如下: 当前的 goroutine 因调用 Wait when the method is blocked, 另一个 goroutine 调用了该值的 Done 方法, 并使其计数器的值变为了 0, 这会唤醒当前的 goroutine, 并使它试图继续执行 Wait 方法中其余的代码.但在这时, 又有一个 goroutine 调用了它的 Add 方法, 并让其计数器的值又从 0 变为了某个正整数.此时, 这里的 Wait 方法就会立即抛出一个 panic.According to the pit 2 和坑 3, 总结如下: 不要把增加其计数器值的操作和调用其 Wait 方法的代码, 放在不同的 goroutine 中执行.换句话说, 要杜绝对同一个 WaitGroup 值的两种操作的并发执行, The standard way should be"先统一 Add, 再并发 Done, 最后 Wait".
1.3. 并发实例: Push
For the concurrency example from the previous chapter, A question was raised at the time: 每消费一条 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, Then it will wake up// 数据统计 SendNotify(t.ID, t.TotalPage, t.TaskPage, t.AppType, t.AppLocal, fails, succs)
1.4. 总结
WaitGroup is out-of-the-box and concurrency-safe, One-to-many can be easily achieved through it goroutine 协作流程, 即: 一个分发子任务的 goroutine, 和多个执行子任务的 goroutine, 共同来完成一个较大的任务.在使用 WaitGroup 值的时候, 我们一定要注意, 千万不要让其中的计数器的值小于 0, 否则就会引发 panic.另外, 我们最好用"先统一 Add, 再并发 Done, 最后 Wait"这种标准方式, 来使用 WaitGroup 值, 尤其不要在调用 Wait 方法的同时, 并发地通过调用 Add 方法去增加其计数器的值, 因为这也有可能引发 panic.
边栏推荐
- PyTorch framework to train linear regression model (CPU and GPU environment)
- PyTorch builds a classification network model (Mnist dataset, fully connected neural network)
- Golang channel channel
- 数据库基础知识一(MySQL)[通俗易懂]
- Hanyuan Hi-Tech G8032 standard ERPS ring network switch Gigabit 4 optical 10 electrical industrial Ethernet switch ring network + WEB management + SNMP VLAN planning
- 基于php网上零食商店管理系统获取(php毕业设计)
- Tinymce plugins [Tinymce扩展插件集合]
- Basic principle of the bulk of the animation and shape the An animation tip point
- An工具介绍之摄像头
- Redis connection pool tool class
猜你喜欢
随机推荐
Yahoo!Answers - data set
【蓝桥杯选拔赛真题48】Scratch跳舞机游戏 少儿编程scratch蓝桥杯选拔赛真题讲解
Five, the function calls
期货公司开户关注的关键点
Classes and objects (upper)
In order to counteract the drop in sales and explore the low-end market, Weilai's new brand products are priced as low as 100,000?
Using the Work Queue Manager (4)
来广州找工作有一个多月了,今天终于有着落了,工资7000
How to disable software from running in the background in Windows 11?How to prevent apps from running in the background in Windows 11
类和对象(中下)
软件测试自学还是报班好?
实数取整写入文件(C语言文件篇)
ECCV 2022|通往数据高效的Transformer目标检测器
An动画基础之元件的图形动画与按钮动画
[Practical skills] APP video tutorial for updating APP in CANFD, I2C, SPI and serial port mode of single-chip bootloader (2022-08-01)
An introduction to the camera
d作者:d的新特性
基于php家具销售管理系统获取(php毕业设计)
Golang Mutex
ECCV 2022 | AirDet: 无需微调的小样本目标检测方法