go sync包(五) WaitGroup

WaitGroup

sync.WaitGroup 可以等待一组 Goroutine 的返回,一个比较常见的使用场景是批量发出 RPC 或者 HTTP 请求:

requests := []*Request{...}
wg := &sync.WaitGroup{}
wg.Add(len(requests))for _, request := range requests {go func(r *Request) {defer wg.Done()// res, err := service.call(r)}(request)
}
wg.Wait()
// In the terminology of the Go memory model, a call to Done
// “synchronizes before” the return of any Wait call that it unblocks.
type WaitGroup struct {noCopy noCopy// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.// 64-bit atomic operations require 64-bit alignment, but 32-bit// compilers only guarantee that 64-bit fields are 32-bit aligned.// For this reason on 32 bit architectures we need to check in state()// if state1 is aligned or not, and dynamically "swap" the field order if// needed.state1 uint64state2 uint32
}
  • noCopy:禁止拷贝。
  • state:state 是 WaitGroup 的状态数据字段,且是一个无符号64 bit的数据,内容包含了 counter , waiter 信息
    • counter 代表目前尚未完成的个数,WaitGroup.Add(n) 将会导致 counter += n, 而 WaitGroup.Done() 将导致 counter–。
    • waiter 代表目前已调用 WaitGroup.Wait 的 goroutine 的个数。

在这里插入图片描述

Add

// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait are released.
// If the counter goes negative, Add panics.
//
// Note that calls with a positive delta that occur when the counter is zero
// must happen before a Wait. Calls with a negative delta, or calls with a
// positive delta that start when the counter is greater than zero, may happen
// at any time.
// Typically this means the calls to Add should execute before the statement
// creating the goroutine or other event to be waited for.
// If a WaitGroup is reused to wait for several independent sets of events,
// new Add calls must happen after all previous Wait calls have returned.
// See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) {statep, semap := wg.state()if race.Enabled {if delta < 0 {// Synchronize decrements with Wait.race.ReleaseMerge(unsafe.Pointer(wg))}race.Disable()defer race.Enable()}// counter 增加数量state := wg.state.Add(uint64(delta) << 32)// 取出 counterv := int32(state >> 32)// 取出 waiterw := uint32(state)if race.Enabled && delta > 0 && v == int32(delta) {// The first increment must be synchronized with Wait.// Need to model this as a read, because there can be// several concurrent wg.counter transitions from 0.race.Read(unsafe.Pointer(&wg.sema))}// counter < 0,panicif v < 0 {panic("sync: negative WaitGroup counter")}// delta > 0 && v == int32(delta) : 表示从 0 开始添加计数值// w!=0 :表示已经有了等待者// 说明说明在调用了 Wait() 方法之后又想加入新的等待者,这种操作是不允许的if w != 0 && delta > 0 && v == int32(delta) {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}if v > 0 || w == 0 {return}// This goroutine has set counter to 0 when waiters > 0.// Now there can't be concurrent mutations of state:// - Adds must not happen concurrently with Wait,// - Wait does not increment waiters if it sees counter == 0.// Still do a cheap sanity check to detect WaitGroup misuse.// 避免并发调用 Add() 和 Wait()if *statep != state {panic("sync: WaitGroup misuse: Add called concurrently with Wait")}// Reset waiters count to 0.// 唤醒所有 waiter*statep = 0for ; w != 0; w-- {runtime_Semrelease(semap, false, 0)}
}

Wait

// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {statep, semap := wg.state()if race.Enabled {_ = *statep // trigger nil deref early race.Disable()}for {// 读取state// 高32位 ==> counter// 低32位 ==> waiterstate := atomic.LoadUint64(statep)v := int32(state >> 32)w := uint32(state)// counter减到0了,returnif v == 0 {// Counter is 0, no need to wait.if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer(wg))}return}// Increment waiters count.// counter 不为0,waiters++if wg.state.CompareAndSwap(state, state+1) {if race.Enabled && w == 0 {// Wait must be synchronized with the first Add.// Need to model this is as a write to race with the read in Add.// As a consequence, can do the write only for the first waiter,// otherwise concurrent Waits will race with each other.race.Write(unsafe.Pointer(semap))}// 阻塞runtime_Semacquire(semap)// 被唤醒,检查state是否等于0// 不为0,说明存在计数值未恢复为0就重用,panicif *statep != 0 {panic("sync: WaitGroup is reused before previous Wait has returned")}if race.Enabled {race.Enable()race.Acquire(unsafe.Pointer(wg))}return}}
}

Done

// Done decrements the WaitGroup counter by one.
func (wg *WaitGroup) Done() {wg.Add(-1)
}

Done 只是调用了 Add() ,将groutine - 1。

小结

  • sync.WaitGroup 必须在 sync.WaitGroup.Wait 方法返回之后才能被重新使用。
  • sync.WaitGroup.Done 只是对 sync.WaitGroup.Add 方法的简单封装,我们可以向 sync.WaitGroup.Add 方法传入任意负数(需要保证计数器非负)快速将计数器归零以唤醒等待的 Goroutine。
  • 可以同时有多个 Goroutine 等待当前 sync.WaitGroup 计数器的归零,这些 Goroutine 会被同时唤醒。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/39688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WebSocket解决方案(springboot 基于Redis发布订阅)

WebSocket 因为一般的请求都是HTTP请求&#xff08;单向通信&#xff09;&#xff0c;HTTP是一个短连接&#xff08;非持久化&#xff09;&#xff0c;且通信只能由客户端发起&#xff0c;HTTP协议做不到服务器主动向客户端推送消息。WebSocket确能很好的解决这个问题&…

基于SpringBoot的漫画网站系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;B/S架构模式、Java技术 工具&#xff1a;Visual Studio、MySQL数据库开发工具 系统展示 首页 用户…

零基础学习MySQL---MySQL入门

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、什么是数据库 问&#xff1a;存储数据用文件就可以了&#xff0c;为什么还要弄个数据库呢&#xff1f; 这就不得不提…

如何在《语文新读写》期刊上发表论文?

如何在《语文新读写》期刊上发表论文&#xff1f; 《语文新读写》知网 省级G4 3版面4800字符数 24年10-11月 可版权页查稿 出刊晚5个月 《语文新读写》栏目&#xff1a;视点_本期特稿、视点_百家争鸣、探索_教材新探、探索_阅读风向、探索_写作杂谈、实践_教法学法、实践_教…

【python】OpenCV—Feature Detection and Matching

参考学习来自OpenCV基础&#xff08;23&#xff09;特征检测与匹配 文章目录 1 背景介绍2 Harris角点检测3 Shi-Tomasi角点检测4 Fast 角点检测5 BRIEF 特征描述子6 ORB(Oriented Fast and Rotated Brief) 特征描述子7 SIFT(Scale Invariant Feature Transform) 特征描述子8 SU…

Milvus ConnectionRefusedError: how to connect locally

题意&#xff1a;怎样在本地连接到 Milvus 数据库。连接 Milvus 数据库被拒绝的错误 问题背景&#xff1a; I am trying to run a RAG pipeline using haystack & Milvus. 我正在尝试使用 haystack 和 Milvus 运行一个 RAG&#xff08;检索增强型生成&#xff09;管道。 …

vue+element-ui简洁完美实现个人博客“​响石潭 ​”

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.生活 ​编辑 4.文章详情 ​编辑 5.关于我 ​编辑 ​编辑 三、源码实现 1.项目依赖package.json 2.项目启动 3.首页源码 四、总结 一、项目介绍 本项目在线预览&#xff1a;点击访问 参考官网&#xff1…

腾讯 TRANSAGENTS: 多智能体翻译框架上线

之前介绍的由腾讯 AI 实验室搞得TRANSAGENTS&#xff08;多 Agent 系统&#xff0c;模拟现实翻译出版流程&#xff09;终于上线演示了&#xff01;提供了基于 GPT-4o 的免费试用, 暂时还是期货开源。

R语言fastshap包进行支持向量机shap可视化分析

1995年VAPINK 等人在统计学习理论的基础上提出了一种模式识别的新方法—支持向量机 。它根据有限的样本信息在模型的复杂性和学习能力之间寻求一种最佳折衷。 以期获得最好的泛化能力.支持向量机的理论基础决定了它最终求得的是全局最优值而不是局部极小值,从而也保证了它对未知…

[数据集][目标检测]围栏破损检测数据集VOC+YOLO格式1196张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1196 标注数量(xml文件个数)&#xff1a;1196 标注数量(txt文件个数)&#xff1a;1196 标注…

40V转5V,40V转3.3V,40V转3V使用什么降压芯片型号?

40V转5V,40V转3.3V,40V转3V使用什么降压芯片型号? # 40V转5V、3.3V、3V降压芯片&#xff1a;AH8820A的介绍与应用 在电子电路设计中&#xff0c;电压转换是一个常见的需求。特别是在需要将较高电压转换为较低电压以供微控制器、传感器和其他低电压设备使用时&#xff0c;降压…

力扣1685.有序数组中差绝对值之和

力扣1685.有序数组中差绝对值之和 记录左边之和 和 右边之和从左到右遍历每个元素 求res class Solution {public:vector<int> getSumAbsoluteDifferences(vector<int>& nums) {int n nums.size(),lsum 0,rsum accumulate(nums.begin(),nums.end(),0);ve…

匿名方法与Lambda表达式

知识集锦 一、lambda表达式介绍 无参数 () >{return "1";}; 等同于 string getnum(){ return "1"; } 有两个参数 (p1, p2) >{ return p1*p2;}; 等同于 int mul(p1, p2) { return p1*p2;}; lambda表达式可以捕获外部变量&#xff0c;并在其主体中使用…

怎么在电脑上录屏?跟着教程一步步操作

随着数字化时代的到来&#xff0c;电脑录屏已经成为一项必备技能。无论是录制游戏画面、制作教程视频&#xff0c;还是保存线上会议记录&#xff0c;录屏都能帮上大忙。可是怎么在电脑上录屏呢&#xff1f;本文将介绍两种在电脑上进行录屏的方法&#xff0c;这两种方法各有特点…

陶建辉当选 GDOS 全球数据库及开源峰会荣誉顾问

近日&#xff0c;第二十三届 GOPS 全球运维大会暨 XOps 技术创新峰会在北京正式召开。本次会议重点议题方向包括开源数据库落地思考、金融数据库自主可控、云原生时代下数据库、数据库智能运维、数据库安全与隐私、开源数据库与治理。大会深入探讨这些方向&#xff0c;促进了数…

宇宙第一大厂亚马逊云科技AWS人工智能/机器学习证书即将上线,一篇文章教你轻松拿下

据麦肯锡《在华企业如何填补AI人才缺口》研究表明&#xff0c;到2030年人工智能为中国带来的潜在价值有望超过1万亿美元&#xff0c;而随着各大企业进入人工智能化&#xff0c;对该领域的人才需求将从目前的100万增长到2030年的600万。然而到保守估计&#xff0c;到2030可以满足…

DevOps:开发与运维的无缝融合

目录 前言1. DevOps的起源与概念1.1 DevOps的起源1.2 DevOps的定义 2. DevOps的核心实践2.1 持续集成2.2 持续交付2.3 自动化 3. DevOps工具链3.1 版本控制系统3.2 持续集成工具3.3 配置管理工具3.4 容器化与编排工具3.5 监控和日志工具 4. DevOps的实际应用4.1 案例分析&#…

C语言实战 | 用户管理系统

近期推出的青少年防沉迷系统&#xff0c;采用统一运行模式和功能标准。在“青少年模式”下&#xff0c;未成年人的上网时段、时长、功能和浏览内容等方面都有明确的规范。防沉迷系统为青少年打开可控的网络空间。 01、综合案例 防沉迷系统的基础是需要一个用户管理系统管理用户…

C# 计算椭圆上任意一点坐标

已知圆心坐标 &#xff08;x0&#xff0c;y0&#xff09;&#xff0c;横轴 A&#xff08;长半轴&#xff09;&#xff0c;竖轴 B&#xff08;短半轴&#xff09;&#xff0c;角度 a&#xff0c;则圆边上点&#xff08;x&#xff0c;y&#xff09;的坐标为&#xff1a; 方法一 …

docker push 推送镜像到阿里云仓库

1.登陆阿里云 镜像服务&#xff0c;跟着指引操作就行 创建个人实例&#xff0c;创建命名空间、镜像仓库&#xff0c;绑定代码源头 2.将镜像推送到Registry $ docker login --username*** registry.cn-beijing.aliyuncs.com $ docker tag [ImageId] registry.cn-beijing.aliy…