Go语言的sync.Once和sync.Cond

一.sync.Once

Once(单次执行)

用途:确保某个操作只执行一次(如初始化配置)

核心方法:Do(f func()):保证 f只执行一次

package mainimport ("fmt""sync"
)var (config map[string]stringonce   sync.Oncewg     sync.WaitGroup
)func loadConfig() {once.Do(func() {fmt.Println("Loading config...")config = map[string]string{"key": "value"}})
}func main() {for i := 0; i < 5; i++ {wg.Add(1)go func() {defer wg.Done() // 确保 goroutine 结束时减少计数器loadConfig()}()}wg.Wait() // 等待所有 goroutine 完成
}

可以确保这个协程只进行一次

二.sync.Cond

sync.Cond 是 golang 标准库提供的并发协调器,用于支援开放人员在指定条件下阻塞和唤醒协程的操作.

  • Wait():释放锁并阻塞,直到被唤醒。
  • Signal():唤醒一个等待的 goroutine。
  • Broadcast():唤醒所有等待的 goroutine。

2.1 数据结构与构造器方法

type Cond struct {// 不可以对其进行值拷贝noCopy noCopy// 一个自旋锁L Locker// 一个队列,存放阻塞的goroutinenotify  notifyListchecker copyChecker
}// NewCond returns a new Cond with Locker l.
func NewCond(l Locker) *Cond {return &Cond{L:l}
}

(1)成员变量 noCopy + checker 是一套组合拳,保证 Cond 在第一次使用后不允许被复制;

(2)核心变量 L,一把锁,用于实现阻塞操作;

(3)核心变量 notify,阻塞链表,分别存储了调用 Cond.Wait() 方法的次数、goroutine 被唤醒的次数、一把系统运行时的互斥锁以及链表的头尾节点.

type notifyList struct {wait   uint32notify uint32lock   uintptr // key field of the mutexhead   unsafe.Pointertail   unsafe.Pointer
}

2.2 Cond.Wait

作用:把当前这个持有锁的goroutine,释放锁,陷入一个被动阻塞的状态,加入阻塞队列里面。

什么时候被唤醒呢?

当有其他的goroutine也持有这个Cond的引用,使用Signal函数的时候,会首先唤醒队首的goroutine

通过这个机制就可以实现异步goroutine的协调,比如需要某一个goroutine实现了某一个动作,另外一个goroutine才可以继续执行的一个场景。

使用的前置条件

看下面的代码我们会发现,它有一个解锁的操作,所以在调用他之前,必须是加锁的状态,只有这样才可以执行,然后陷入被动阻塞的状态,阻塞唤醒之后,才会重新加锁。

func (c *Cond) Wait() {c.checker.check()t := runtime_notifyListAdd(&c.notify)c.L.Unlock()runtime_notifyListWait(&c.notify, t)c.L.Lock()
}

(1)检查 Cond 是否在使用过后被拷贝,是则 panic;

(2)该 Cond 阻塞链表 wait 统计数加 1;

(3)当前协程释放锁,因为接下来即将被操作系统 park;

(4)将当前协程包装成节点,添加到 Cond 的阻塞队列当中,并调用 park 操作将当前协程挂起;

(5)协程被唤醒后,重新尝试获取锁.

2.3 Cond.Signal

作用:就是唤醒队首的goroutine唤醒

func (c *Cond) Signal() {c.checker.check()runtime_notifyListNotifyOne(&c.notify)
}

(1)检查 Cond 是否在首次使用后被拷贝,是则 panic;

(2)该 Cond 阻塞链表 notify 统计数加 1;

(3)从头开始遍历阻塞链表,唤醒一个等待时间最长的 goroutine.

2.4 Cond.BroadCast

作用:就是将阻塞队列里面的所有goroutine都进行唤醒。

func (c *Cond) Broadcast() {c.checker.check()runtime_notifyListNotifyAll(&c.notify)
}

(1)检查 Cond 是否在首次使用后被拷贝,是则 panic;

(2)取 wait 值赋值给 notify;

(3)唤醒阻塞链表所有节点.

2.5 使用案例

package mainimport ("fmt""sync""time"
)func main() {var mu sync.Mutexcond := sync.NewCond(&mu)// 共享状态isReady := false// 等待条件的goroutinego func() {fmt.Println("等待者: 等待条件满足...")cond.L.Lock()defer cond.L.Unlock()// 使用循环防止虚假唤醒for !isReady {cond.Wait() // 释放锁并阻塞,唤醒时会重新获得锁fmt.Println("等待者: 被唤醒,检查条件")}fmt.Println("等待者: 条件已满足!")}()// 改变条件的goroutinego func() {time.Sleep(2 * time.Second) // 模拟耗时操作fmt.Println("触发者: 准备改变条件...")cond.L.Lock()isReady = truecond.L.Unlock()fmt.Println("触发者: 发送通知")cond.Signal() // 唤醒一个等待的goroutine}()time.Sleep(3 * time.Second) // 等待所有goroutine完成
}

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

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

相关文章

java整合itext pdf实现自定义PDF文件格式导出

springBoot结合itext pdf实现自定义PDF文件格式导出背景需求&#xff1a;使用PDF导出指定人员对应周次的打卡记录&#xff0c;每周对应星期几打卡过就打“√”。如下图&#xff1a;1、导入依赖导入itextpdf依赖<!-- itex PDF --> <dependency><groupId>…

从0开始学习计算机视觉--Day07--神经网络

当我们输入的变量是一个比较大的向量&#xff08;比如有4096项&#xff09;&#xff0c;函数是求返回输入的最大值&#xff0c;要求的权重矩阵的梯度就是4096 * 4096的大小&#xff0c;而实际上我们的输入往往都不只有一个向量&#xff0c;那如果向量有一百个的话&#xff0c;是…

MySQL存储过程全解析

1、存储过程的概念 存储过程是事先经过编译并存储在数据库中的一段sql语句的集合&#xff0c;调用存储过程可以简化应用开发人员的很多工作&#xff0c;减少数据在数据库和应用服务器之间的传输&#xff0c;对于提高数据处理效率是很有好处。 2、存储过程的优点 存储过程是通…

后端密码加密:守护用户数据的钢铁长城

&#x1f512;“系统被拖库了&#xff01;” 这可能是开发者最恐惧的噩梦。而当用户密码以明文暴露时&#xff0c;灾难将席卷每个用户——密码重用的惯性会让黑客轻松攻破他们在其他平台的账户。作为后端开发者&#xff0c;我们握有守护用户安全的第一道钥匙&#xff1a;科学的…

Flutter 3.29+使用isar构建失败

执行命令&#xff1a;flutter build apk --release 报错 Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!FAILURE: Build failed with an exception. …

SQL 转 Java 实体类工具

拿到数据库建表语句后怎么高效写 Java 实体类&#xff1f;这款工具直接帮你全自动生成&#xff01; 作为一名后端 Java 工程师&#xff0c;你是不是也经历过以下情况&#xff1a; ✅ 拿到一份完整的建表 SQL&#xff0c;却要手动写 Java Bean ✅ 字段几十个&#xff0c;嵌套复…

创客匠人视角下:创始人 IP 打造与知识变现的深度耦合路径

在知识经济蓬勃发展的当下&#xff0c;创始人 IP 打造与知识变现的融合已成为行业破局关键。创客匠人作为深耕知识付费赛道多年的服务平台&#xff0c;其创始人老蒋提出的 “土壤构建能力” 理论&#xff0c;为理解这一融合逻辑提供了独特视角。从本质来看&#xff0c;创始人 I…

【网络协议安全】任务13:ACL访问控制列表

目录 一、概念 1、前言 2、应用场景 3、ACL分类 基于ACL标识方法的划分 基于对IPv4和IPv6支持情况的划分 基于ACL规则定义方式的划分 4、ACL的基本原理 ACL的组成 ACL的匹配机制 5、ACL常用匹配原则 6、ACL常用的匹配项 生效时间段 IP承载的协议类型 源/目的IP…

TensorFlow 安装使用教程

一、TensorFlow 简介 TensorFlow 是由 Google 开发的开源深度学习框架&#xff0c;支持数据流图计算&#xff0c;可运行于 CPU/GPU/TPU。它被广泛应用于语音识别、图像处理、自然语言处理等多个 AI 领域。 二、安装 TensorFlow 2.1 pip 安装&#xff08;默认 CPU 版本&#x…

腾讯云认证考试报名 - TDSQL数据库交付运维专家(TCCE MySQL版)

数据库交付运维专家- 腾讯云TDSQL(MySQL版) 适合人群&#xff1a; 适合TDSQL(MySQL版)各组件扩缩容、运维、性能优化、故障解决、压力测试等数据库开发、运维、管理人员。 认证考试&#xff1a; 单选*40道多选*20道上机*20道 考试时长&#xff1a; 理论考试120分钟,上机考试…

webUI平替应用,安装简单,功能齐全

前言 在安装本地大模型后&#xff0c;我们都会为大模型安装一个用户界面&#xff0c;这样就可以实现语音输入&#xff0c;对话保存&#xff0c;微调&#xff0c;构建本地知识库等高阶功能。 目前最火的本地大模型UI&#xff0c;就是gihub上的webUI&#xff0c;但他不仅依赖较…

【Maven】Maven核心机制的 万字 深度解析

Maven核心机制的万字深度解析一、依赖管理机制全解&#xff08;工业级依赖治理方案&#xff09;1. 坐标体系的本质与设计哲学2. 依赖传递与仲裁算法的工程实现**冲突仲裁核心算法**企业级仲裁策略3. Scope作用域的类加载隔离原理4. 多级仓库体系架构设计二、构建生命周期底层原…

暑期前端训练day4

今天主要是有关周赛的&#xff0c;比赛的时候是用c写的并且是 ak了&#xff0c;但是就是想用js再复盘一下&#xff0c;也不能只是图一时之爽&#xff0c;如果是换在实际的场景里面我是不是只会用 c快速写出来。 最近也要从js逐渐转向ts&#xff0c;感觉Ts才是主旋律&#xff0c…

转Go学习笔记(2)进阶

前置&#xff1a;转Go学习笔记1语法入门 目录Golang进阶groutine协程并发概念梳理创建goroutine语法channel实现goroutine之间通信channel与range、selectGoModulesGo Modules与GOPATHGo Modules模式用Go Modules初始化项目修改模块的版本依赖关系Go Modules 版本号规范vendor …

无人机3控接力模式技术分析

一、运行方式 1. 接力控制流程 位置触发切换&#xff1a;飞控中心实时监测无人机位置&#xff0c;当进入预设的切换路线&#xff08;如靠近下一个机库或控制器覆盖范围&#xff09;时&#xff0c;触发切换流程。 控制权请求与验证&#xff1a; 当前控制器&#xff08…

Actor Critic对比PGValue-Based

目录 回顾一下policy gradient&#xff1a; QAC算法&#xff1a; A2C- advantage actor critic 问题&#xff1a; 1. 为什么要结合起来&#xff0c;能解决什么问题&#xff1f; 1. 策略梯度 (PG) 的优势与核心问题 2. 基于价值方法 (Value-Based) 的优势与局限性 3. 潜…

buuctf-re

1.findKey 打开是C而且有点乱,所以找关键步骤有一个加密进去是不能反编译的,有花指令, 这里有重复的部分把下面的NOP掉,重新定义函数’p’ 之后分析逻辑, // positive sp value has been detected, the output may be wrong! int __userpurge sub_40191F<eax>(int a1&l…

RuoYi、Vue CLI 和 uni-app 结合构建跨端全家桶方案

将 RuoYi、Vue CLI 和 uni-app 结合构建跨端全家桶方案&#xff0c;可以实现一套代码管理后台系统&#xff08;PC&#xff09;和移动端应用&#xff08;H5/小程序/App&#xff09;。以下是整合思路和关键步骤&#xff1a; 技术栈分工 RuoYi&#xff1a;后端框架&#xff08;Spr…

二十九、windows系统安全---windows注册表安全配置

环境 windows server 2012 原理 注册表简介: 注册表&#xff08;Registry&#xff0c;繁体中文版Windows操作系统称之为登录档&#xff09;是Microsoft Windows中的一个重要的数据库&#xff0c;用于存储系统和应用程序的设置信息。早在Windows 3.0推出OLE技术的时候&#…

Android 一帧绘制流程

Android 一帧绘制流程揭秘&#xff1a;主线程与 RenderThread 的双人舞 核心目标&#xff1a;60帧/秒的丝滑体验&#xff0c;意味着每帧必须在16.67ms内完成所有工作&#xff01; 想象一下屏幕刷新就像放映电影&#xff0c;一帧接一帧。Android系统为了播放这“电影”&#xff…