Go中sync 包的 Once 使用

news2025/1/19 14:31:50

文章目录

    • 背景
    • One 简介
    • 示例
    • 注意
    • 源码解读

背景

在系统初始化的时候,某些代码只想被执行一次,这时应该怎么做呢,没有学习 Once 前,大家可能想到 声明一个标识,表示是否初始化过,然后初始化这个标识加锁,更新这个标识。
但是学会了 One 的使用可以更加简单的解决这个问题

One 简介

Once 包主要用于在并发执行代码的时候,某部分代码只会被执行 一次。
Once 的使用也非常简单,Once 只有一个 Do 方法,接收一个无参数无返回值的函数类型的参数 f,不管调用多少次 Do 方法,参数 f 只在第一次调用 Do 方法时执行。

示例

我们有一个Msg 参数,多个协程都会用到他,但是这个参数只用初始化一次就可以。

package main

import (
	"fmt"
	"sync"
	"time"
)
var msg string
func main() {
	var one sync.Once
	for i := 0; i < 5; i++ {
		go func(i int) {
			one.Do(func() { 
				fmt.Printf("%d 执行初始化!\n", i)
				msg = "Your Need Data"
			})
			fmt.Println(msg)
		}(i)
	}
	time.Sleep(3* time.Second)
}

执行结果如下:
在这里插入图片描述
可以看到初始化的代码只被4号线程执行了一次, 其他协程都是直接读的初始化的数据,并没有执行初始化的函数。

注意

不要在 Do() 方法的参数方法中再次调用Do() 方法,因为执行这个Do() 方法的参数方法的时候,One 会持有一个锁,如果再参数方法中再次调用Do() 方法,就会等待这个锁释放, 导致参数方法无法执行完毕,然后外层的Do 方法就一直无法释放锁,最后就成了死锁。
错误示例:

package main

import (
	"fmt"
	"sync"
)
var msg string
var one sync.Once
func main() {
	one.Do(fun1)
}

func fun1(){
	fmt.Println("我是 fun1")
	one.Do(fun2)
}

func fun2(){
	fmt.Println("我是 fun2")
}

执行结果:
在这里插入图片描述
可以知道再 fun1() 中使用 Do() 方法调用 fun2 的时候形成了死锁, 因为在 fun1() 执行过程中已将持有了该锁,需要 fun1() 执行完毕才会释放,然后因为使用 Do() 方法执行 fun2() 也会请求这个锁, 会一直等待,导致 fun1() 不可能执行完, 也不可能释放锁。成了死锁。

源码解读

查看源码

func (o *Once) Do(f func()) {

	if atomic.LoadUint32(&o.done) == 0 {
		// Outlined slow-path to allow inlining of the fast-path.
		o.doSlow(f)
	}
}

func (o *Once) doSlow(f func()) {
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
		defer atomic.StoreUint32(&o.done, 1)
		f()
	}
}

使用一个原子类作为标识,加锁校验和操作原子类,保证只会被一个协程执行。
Do 调用了 doSlow , 在 doSlow 中有defer 关键字,表示执行函数和释放锁是倒序执行,必须先执行完毕 if 判断和里面的 f() 才能释放锁。

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

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

相关文章

Lazada(来赞达)箱包什么产品好卖?东南亚热销国家选品分析

东南亚市场&#xff1a;存在巨大的跨境电商出口机遇 和2021年前对比&#xff0c;2022年越南、马来西亚等东南亚国家普遍实现了贸易正增长&#xff0c;欧美国家则多仍处于负增长状态。 同时2022年欧美等发达经济体通胀压力迅速抬升&#xff0c;这直接影响到国家间货币汇率&…

微信小程序如何配置并使用less?

微信小程序如何配置并使用less&#xff1f;1、在VScode中下载Less插件2、在微信小程序中依次点击如下按钮3、选中刚在vscode中下载安装的插件文件4、在设置中选中编辑器设置5、找到less进行json配置6、在json文件中的less.compile添加如下配置7、如何使用1、在VScode中下载Less…

深圳大学计软《面向对象的程序设计》实验7 拷贝构造函数与复合类

A. Point&Circle(复合类与构造) 题目描述 类Point是我们写过的一个类&#xff0c;类Circle是一个新的类&#xff0c;Point作为其成员对象&#xff0c;请完成类Circle的成员函数的实现。 在主函数中生成一个圆和若干个点&#xff0c;判断这些点与圆的位置关系&#xff0c;…

最佳iOS设备管理器imazing 2.16.9官网Mac/Windows下载电脑版怎么下载安装

imazing 2.16.9官网Mac/Windows下载电脑版是款针对苹果设备所打造的管理工具。iMazing为用户提供多种设备管理功能&#xff0c;每一位用户都能以自己的形式管理苹果设备。iMazing与苹果设备连接后&#xff0c;用户就可以轻松传输文件&#xff0c;浏览保存信息等。 应用介绍 iM…

员工入职流程自动化的原因

人和人之间的第一印象非常重要&#xff0c;一段缘分能不能开始&#xff0c;就看第一印象够不够给力了。其实&#xff0c;公司和新员工之间也存在着这样的关系&#xff0c;但也有些许差别。公司对新员工的第一印象&#xff0c;更多是从第一次见面的时候就产生了&#xff0c;而新…

Flutter知识点(三)修改flutter工程名和包名

修改包名, 修改五个地方&#xff1a; debug/AndroidManifest.xml, main/AndroidManifest.xml, profile/AndroidManifest.xml,gradle.build的中application id,原生的android代码&#xff0c; 这一块建议用android工程的方式打开。不然无法使用refactor修改名字。 修改flutter工…

延迟队列实现订单超时自动取消

在上一篇 Java 实现订单未支付超时自动取消&#xff0c;使用Java自带的定时任务TimeTask实现订单超时取消&#xff0c;但是有小伙伴提出这种实现&#xff0c;会有以下几个问题&#xff1a; 线上服务挂了&#xff0c;导致服务下所有的定时任务失效。服务重启&#xff0c;定时任…

buuctf-pwn write-ups (10)

文章目录buu073-hitcontraining_bambooboxbuu074-cmcc_pwnme2buu075-picoctf_2018_got-shellbuu076-npuctf_2020_easyheapbuu077-wdb_2018_2nd_easyfmtbuu078-PicoCTF_2018_can-you-gets-mebuu079-mrctf2020_easy_equationbuu080-ACTF_2019_babystackbuu081-mrctf2020_shellcod…

C语言每日一题】——杨氏矩阵

【C语言每日一题】——倒置字符串&#x1f60e;前言&#x1f64c;杨氏矩阵&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者简介…

WebGL系列教程 — 绘制点(版本2、版本3、版本4、版本5)

目录 0.WebGL简介&#xff1a; 绘制一个点 绘制一个点&#xff08;版本2&#xff09; 绘制一个点&#xff08;版本3&#xff09; 绘制一个点&#xff08;版本4&#xff09; 实现 绘制一个点&#xff08;版本5&#xff09; 0.WebGL简介&#xff1a; WebGL是一种用于在We…

Linux学习第六节-Facl访问控制列表

1.概念 FACL&#xff08;Filesystemctl Access Control List &#xff09; 文件系统访问控制列表&#xff1a;利用文件扩展属性保存额外的访问控制权限&#xff0c;单独为每一个用户量身定制一个权限。 命令格式&#xff1a; setfacl [选项] 归属关系:用户名:权限 目录 常用选…

【数据结构起航】:衡量算法的好坏--时间空间复杂度

时间复杂度和空间复杂度 文章目录时间复杂度和空间复杂度1.算法效率1.1算法复杂度1.2复杂度在OJ里的应用2.时间复杂度2.1时间复杂度的概率2.2大O渐进表示法推导大O阶方法&#xff1a;2.3时间复杂度的举例计算3.空间复杂度3.1空间复杂度的举例计算4.复杂度各量级对比1.算法效率 …

ECharts数据可视化库--导入EChars库

目录 一.ECharts基本认识 二.EChars库导入 1.下载echart.js文件 2.在IDEA引入eharts.js 三.数据可视化绘制 最快乐的学习就是从繁入简&#xff0c;虽然此文章比较简短&#xff0c;但花最少的时间学最多的技能是真的香&#xff0c;点个关注吧&#xff01;这个是数据可视化的…

Kubernetes三 Kubernetes之Pod控制器与service详解

KubernetesPod详解 一 Pod控制器详解 1.1 Pod控制器介绍 Pod是kubernetes的最小管理单元&#xff0c;在kubernetes中&#xff0c;按照pod的创建方式可以将其分为两类&#xff1a; 自主式pod&#xff08;不推荐&#xff09;&#xff1a;kubernetes直接创建出来的Pod&#xf…

MDK Keil查看map文件及编译占用内存信息、函数入口地址

一、在哪里打开map文件查看&#xff08;1&#xff09;第一种&#xff0c;在keil软件下&#xff0c;双击你的工程名&#xff0c;map就会弹出&#xff08;2&#xff09;第二种&#xff0c;点击魔术棒&#xff0c;查看 Lis文件输出的位置入口我的在output...文件下&#xff0c;那我…

努力构建15分钟听力圈,腾讯天籁行动助力听障老人更快融入数字社会

3月3日&#xff0c;腾讯与北京听力协会联合举办线上技术研讨会&#xff0c;以“AI助听技术发展与应用创新”为主题&#xff0c;汇聚国内从事AI助听、辅听相关理论研究及前沿技术落地的专家学者&#xff0c;共同探讨当前人工智能在听力健康领域的研究热点和实践成果。会上&#…

得物供应链复杂业务实时数仓建设之路

1 背景 得物供应链业务是纷繁复杂的&#xff0c;我们既有 JIT 的现货模式中间夹着这大量的仓库作业环节&#xff0c;又有到仓的寄售&#xff0c;品牌业务&#xff0c;有非常复杂的逆向链路。在这么复杂的业务背后&#xff0c;我们需要精细化关注人货场车的效率和成本&#xff…

Malware Dev 03 - 隐匿之 Command Line Spoofing 原理解析

写在最前 如果你是信息安全爱好者&#xff0c;如果你想考一些证书来提升自己的能力&#xff0c;那么欢迎大家来我的 Discord 频道 Northern Bay。邀请链接在这里&#xff1a; https://discord.gg/9XvvuFq9Wb我拥有 OSCP&#xff0c;OSEP&#xff0c;OSWE&#xff0c;OSED&…

浅分析BIG-建筑展示系统

一、主页&#xff08;主要界面&#xff09;重点疑点&#xff08;需要解决&#xff09;1.云平台实时同步。是否可以电脑与hololens2同步或链接&#xff1f;并可以传输信息提醒&#xff1f;一级界面&#xff08;启动界面&#xff09;1.交互式启动激活效果&#xff08;触发按钮旋转…

TCP协议三次握手的原因是什么?为什么不用两次握手和4次握手?

今天复习了TCP协议的三次握手&#xff0c;对上一篇C网络编程有了更深的理解。当时考研的时候计网学过&#xff0c;这里再总结一下分享。网图都是截图来的&#xff0c;侵删。TCP协议属于传输层协议&#xff0c;上面的应用层协议包括HTTP、FTP之类&#xff0c;应用层协议是最接近…