当前位置: 首页 > backend >正文

Golang WaitGroup 用法 源码阅读笔记

使用

sync.WaitGroup可以用来阻塞等待一组并发任务完成

下面是如何使用sync.WaitGroup的使用

最重要的就是不能并发调用Add()Wait()

var wg sync.WaitGroupfor ... {wg.Add(1) // 不能和wg.Wait()并发执行go func() {// 不能在启动的函数里面执行wg.Add(), 否则会panicdefer wg.Done()// dosomething} ()
}wg.Wait()

下面是官方示例

package mainimport ("sync"
)type httpPkg struct{}func (httpPkg) Get(url string) {}var http httpPkgfunc main() {var wg sync.WaitGroupvar urls = []string{"http://www.golang.org/","http://www.google.com/","http://www.example.com/",}for _, url := range urls {// Increment the WaitGroup counter.wg.Add(1)// Launch a goroutine to fetch the URL.go func(url string) {// Decrement the counter when the goroutine completes.defer wg.Done()// Fetch the URL.http.Get(url)}(url)}// Wait for all HTTP fetches to complete.wg.Wait()
}

源码解读

结构体

type WaitGroup struct {noCopy noCopystate atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count.sema  uint32
}

noCopy标识结构体不能被复制

state的高32位表示counter的值,低32位表示waiter的值

sema用来阻塞和唤醒goroutine

方法

  • <font style="color:rgb(36, 41, 46);background-color:rgb(233, 236, 239);">func(wg *WaitGroup) Done()</font>
  • <font style="color:rgb(36, 41, 46);background-color:rgb(233, 236, 239);">func(wg *WaitGroup) Add(delta int)</font>
  • <font style="color:rgb(36, 41, 46);background-color:rgb(233, 236, 239);">func(wg *WaitGroup) Wait()</font>

Done()

// Done 将计数器(counter)值减 1
func (wg *WaitGroup) Done() {wg.Add(-1)
}

调用了add方法

Add()

func (wg *WaitGroup) Add(delta int) {state := wg.state.Add(uint64(delta) << 32)v := int32(state >> 32) // counter数量w := uint32(state) // waiter数量// counter < 0 -->> panicif v < 0 {panic("sync: negative WaitGroup counter")}// 并发调用Add、Wait-->> panicif w != 0 && delta > 0 && v == int32(delta) {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}// 操作成功if v > 0 || w == 0 {return}// 并发调用panicif wg.state.Load() != state {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}// v == 0 && counter != 0// 释放等待的waiter,将state的状态置为0wg.state.Store(0)for ; w != 0; w-- {runtime_Semrelease(&wg.sema, false, 0)}
}

从源码的panic来看,不能并发调用Add()&Wait()

不能让counter < 0

Wait()

func (wg *WaitGroup) Wait() {// CAS操作失败后for {state := wg.state.Load()v := int32(state >> 32)w := uint32(state)if v == 0 {// counter == 0 直接返回,没有需要等待的goroutinereturn}// if wg.state.CompareAndSwap(state, state+1) {runtime_SemacquireWaitGroup(&wg.sema)// 检验,唤醒前就已经将state置为0if wg.state.Load() != 0 {panic("sync: WaitGroup is reused before previous Wait has returned")}return}}
}

总结

参考

https://segmentfault.com/a/1190000045998688

http://www.xdnf.cn/news/3708.html

相关文章:

  • # LeetCode 1007 行相等的最少多米诺旋转
  • 动态规划-1137.第N个泰波那契数-力扣(LeetCode)
  • 【iview】es6变量结构赋值(对象赋值)
  • 【LLaMA-Factory实战】1.3命令行深度操作:YAML配置与多GPU训练全解析
  • 轻量级RTSP服务模块:跨平台低延迟嵌入即用的流媒体引擎
  • 从融智学视域快速回顾世界历史和主要语言文字最初历史证据(列表对照分析比较)
  • Vue实现成绩增删案例
  • C++ 中的继承
  • JSON 处理笔记
  • npm pnpm yarn 设置国内镜像
  • 数据库原理与应用实验二 题目七
  • PowerShell安装Chocolatey
  • 哈希函数详解(SHA-2系列、SHA-3系列、SM3国密)案例:构建简单的区块链——密码学基础
  • Python刷题:流程控制(下)
  • PowerPC架构详解:定义、应用及特点
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】1.1 数据库核心概念与PostgreSQL技术优势
  • C++负载均衡远程调用学习之 Dns-Route关系构建
  • 代码随想录算法训练营Day43
  • 超预期!淘宝闪购提前开放全国全量,联合饿了么扭转外卖战局
  • 美丽天天秒链动2+1源码(新零售商城搭建)
  • P4314 CPU 监控 Solution
  • YOLO旋转目标检测之ONNX模型推理
  • 上位机知识篇---粗细颗粒度
  • P2415集合求和 题解
  • 【Java IO流】字符输入流FileReader、字符输出流FileWriter
  • C++ 动态内存管理详讲
  • 【Java IO流】字节输入流FileInputStream、字节输出流FileOutputStream
  • ICRA 2025 基于触觉反馈的闭环分层控制框架——开放环境下通用门开启的智能规划与操作
  • 【unity游戏开发入门到精通——UGUI】实现精准点击异形或者不规则图片button按钮
  • 字符串的相关方法