sync.waitGroup 原理分析

前言#

sync的常用包好像都快讲完了, 最近几天进度很快啊, 希望能多多保持.

sync.WaitGroup是为了解决任务编排而出现的, 主要就是解决并发-等待问题, 因此在真正编写过程中也很常用, 本篇大致讲解其内部实现的方式

Demo#

简单介绍一下用法

func main() {
	wg := sync.WaitGroup{}
	wg.Add(1) // wg计数+1
	go func() {
		defer wg.Done() // wg计数-1
		time.Sleep(3 * time.Second)
	}()
	wg.Wait() // 等待 wg 结束(wg计数为0)
}

对应sync.WaitGroup来讲, 只有三种方法:

  • Add(delta int): 为计数器添加一定的数字
  • Done(): 为计数器数字减去1
  • Wait(): 夯住等待计数器数字变成0

结构#

和往常一样, 先从结构开始看起

type WaitGroup struct {
    // 避免复制使用的一个技巧,可以告诉vet工具违反了复制使用的规则
    noCopy noCopy
    // 64bit(8bytes)的值分成两段,高32bit是计数值,低32bit是waiter的计数
    // 另外32bit是用作信号量的
    // 因为64bit值的原子操作需要64bit对齐,但是32bit编译器不支持,所以数组中的元素在不同的架构中不一样,具体处理看下面的方法
    // 总之,会找到对齐的那64bit作为state,其余的32bit做信号量
    state1 [3]uint32
}
  • noCopy: 这个是一个使用技巧, 如果一个结构体中有此字段, vet 工具会在编译时检查避免被 copy 使用
  • state1: 从定义可以看出, 其长度为3, 每个32bit, 里面包含了waitGroup的计数值和信号量和 waiter 计数

state1 结构

state[0]  // 调用 wait 等待的 goroutine 数量
state[1]  // 计数
state[2]  // 信号量

Add#

Add主要是对state1字段中的计数值部分进行操作, 步骤如下:

  1. 将参数delta左移32位
  2. 将值加到计数值上(state1[1]), 这个值是可负可正

Done#

Done实际上就是调用Add(-1)

而检测到-1之后的计数值为0时, 通过信号量唤醒正在wait的阻塞协程

Wait#

调用wait时, 会将waiter+1, 然后将自身加入到等待队列中并阻塞, 等待Done时的唤醒

作者:chnmig

出处:https://www.cnblogs.com/chnmig/p/16744182.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   ChnMig  阅读(159)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu