golang并发安全-sync.Once

news2024/11/27 23:55:03

什么是sync.Once

sync.Once 是 Go 语言中的一种同步原语,用于确保某个操作或函数在并发环境下只被执行一次。它只有一个导出的方法,即 Do,该方法接收一个函数参数。在 Do 方法被调用后,该函数将被执行,而且只会执行一次,即使在多个协程同时调用的情况下也是如此。

例子

func main() {
	var once sync.Once
	for i := 0; i < 5; i++ {
		go func(i int) {
			fun1 := func() {
				fmt.Printf("i:=%d\n", i)
			}
			once.Do(fun1)
		}(i)
	}
	time.Sleep(1 * time.Second)
}

无论执行多少次,仅返回 i:=0

看看源码

//Once 是一个只执行一次的对象。
//Once 首次使用后不得复制一次。
type Once struct {
    //done表示动作是否已执行。
    // 它在结构中是第一个,因为它在hot路径中使用。
    // 热路径在每个调用站点都是内联的
    done uint32
    m    Mutex
}

唯一的对外开放函数(Do)

func (o *Once) Do(f func()) {
   //one为0则表示未执行过,调用doSlow()方法初始化
	if atomic.LoadUint32(&o.done) == 0 {
		// Outlined slow-path to allow inlining of the fast-path.
		o.doSlow(f)
	}
}

Do(f) 被调用多次,即使f在每次调用中都有不同的值,只有第一次调用才会调用f。

func (o *Once) doSlow(f func()) {
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 { // 双重检查,避免 f 已被执行过
		defer atomic.StoreUint32(&o.done, 1)
		f()
	}
}

只有done == 0 才会被释放,并且使用defer保证 f()执行完会讲done置1

我们说说Once一些其他的事吧

不要嵌套 同一个once

func main() {
	var once sync.Once
	for i := 0; i < 5; i++ {
		once.Do(func() {
			once.Do(func() {
				fmt.Println(1)
			})
		})
	}
	time.Sleep(1 * time.Second)
}

直接报错:

作者在代码中提示我们:因为在对f的一个调用返回之前,不会返回对Do的调用,所以如果f导致调用Do,它将死锁。

解释 atomic.CompareAndSwapUint32 为什么不行

作者提到了 atomic.CompareAndSwapUint32 是存在问题:给定两个同时调用,cas的获胜者将调用f,第二个将立即返回,而无需等待第一个对f的调用完成。

func (o *Once) Do(f func()) {
	if atomic.CompareAndSwapUint32(&o.done, 0, 1) {
		f()
	}
}

虽然 cas 保证了同一时刻只有一个请求进入 if 判断执行 f()。但是其它的请求却没有等待 f() 执行完成就立即返回了。那么用户端在执行 once.Do 返回之后其实就可能存在 f() 还未完成,就会出现意料之外的错误。如下面例子

type OnceSelf struct {
	done uint32
}

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

	if atomic.CompareAndSwapUint32(&o.done, 0, 1) {f() }
}

func main() {
	var b map[string]int
	var once OnceSelf
	go func() {
		once.Do(func() {
			b = make(map[string]int, 10)
		})
	}()
	b["1"] = 1
	fmt.Println(b)

}

会存在问题

init 和 once区别

  • init 函数是在文件包首次被加载的时候执行,且只执行一次
  • sync.Onc 是在代码运行中需要的时候执行,且只执行一次

链接

what-is-fast-path-slow-path-hot-path

what-does-hot-path-mean-in-the-context-of-sync-once

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

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

相关文章

Python算法题集_搜索二维矩阵II

Python算法题集_搜索二维矩阵II 题41&#xff1a;搜索二维矩阵II1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【双层循环】2) 改进版一【行尾检测】3) 改进版二【对角线划分】 4. 最优算法 本文为Python算法题集之一的代码示例 题41&#xf…

Oracle 面试题 | 12.精选Oracle高频面试题

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

国辰智企APS自动化排产平台:实现生产计划与其他系统无缝协同

在当今竞争激烈的制造环境中&#xff0c;有效的生产计划和排程对于企业的成功至关重要。APS生产计划排程平台作为一种先进的工具&#xff0c;正越来越受到企业的关注和应用。那么&#xff0c;APS生产计划排程平台有哪些类型呢&#xff1f;本文将为您详细介绍。 1.基于规则的APS…

Java学习-内部类

内部类概述 1.成员内部类 注意&#xff1a; 2.静态内部类 3.局部内部类&#xff08;看看就行&#xff09; 4.匿名内部类 应用场景&#xff1a;通常作为一个参数传给方法 Eg.小猫和小狗都参加游泳比赛

Open CASCADE学习|分割曲线

1、通过参数进行分割 分别获得曲线的 FirstParameter 和 LastParameter &#xff0c;然后对参数进行分割&#xff0c;获得n个ui&#xff0c;并对每个ui调用D0&#xff08;获得这个点的坐标值&#xff09;或D1&#xff08;获得这个点的坐标值和切向量&#xff09;。这个方法的优…

【MySQL进阶】事务原理

文章目录 事务机制基本介绍事务管理基本操作提交方式事务 ID 隔离级别四种级别加锁分析 原子特性实现方式实现原理undo log 隔离特性实现方式MVCC实现原理隐藏字段undo logRead View RC RR 持久特性实现方式redo log 一致特性 面试题MySQL的ACID特性分别是怎么实现的&#xff1…

AES算法:数据传输的安全保障

在当今数字化时代&#xff0c;数据安全成为了一个非常重要的问题。随着互联网的普及和信息技术的发展&#xff0c;我们需要一种可靠的加密算法来保护我们的敏感数据。Advanced Encryption Standard&#xff08;AES&#xff09;算法应运而生。本文将介绍AES算法的优缺点、解决了…

React 中实现拖拽功能-插件 react-beautiful-dnd

拖拽功能在平时开发中是很常见的&#xff0c;这篇文章主要使用react-beautiful-dnd插件实现此功能。 非常好用&#xff0c;附上GitHub地址&#xff1a;https://github.com/atlassian/react-beautiful-dnd 安装及引入 // 1.引入 # yarn yarn add react-beautiful-dnd# npm npm…

在java中获取excel的cell值的时候报错

在获取cell的时候&#xff0c;通常会有报错类型不匹配的问题&#xff0c;这是因为你的cell中存储的数据类型和使用的方法不匹配的原因&#xff0c;假如说cell中存储了一个数字&#xff0c;但是使用的cell.getStringCellValue()获取值&#xff0c;就会有如下错误 java.lang.Ill…

LabVIEW智能温度直流模件自动测试系统

LabVIEW智能温度直流模件自动测试系统 自动化测试系统在提高测试效率和准确性方面发挥着越来越重要的作用。介绍了一种基于LabVIEW的智能温度直流模件&#xff08;TDCA&#xff09;自动测试系统的设计与实施&#xff0c;旨在提高测控装置的产品质量。 系统的硬件平台主要由PS…

Facebook群控:利用IP代理提高聊单效率

在当今社交媒体竞争激烈的环境中&#xff0c;Facebook已经成为广告营销和推广的重要平台&#xff0c;为了更好地利用Facebook进行推广活动&#xff0c;群控技术应运而生。 本文将深入探讨Facebook群控的定义、作用以及如何利用IP代理来提升群控效率&#xff0c;为你提供全面的…

13.从桥接模式细品人生的几座桥

“物理学不存在了&#xff0c;今后也不会存在。”——《三体》 在《三体》中&#xff0c;有这样一个桥段&#xff0c;顶级的物理学家杨冬在三体文明超级计算机“智子”的干扰和误导下&#xff0c;得出了物理实验的结果在实验之前就会被某种力量确定的结论&#xff0c;导致自己…

【Spring】代理模式

文章目录 代理模式对代理模式的理解静态代理动态代理JDK动态代理原理源码优化 CGLIB动态代理使用原理 JDK与CGLIB的对比 面试题JDK动态代理和CGLIB有什么区别&#xff1f;既然有没有接口都可以用CGLIB&#xff0c;为什么Spring还要使用JDK动态代理&#xff1f; 代理模式 对代理…

数据库管理phpmyadmin

子任务1-PHPmyadmin软件的使用 本子任务讲解phpmyadmin的介绍和使用操作。 训练目标 1、掌握PHPmyadmin软件的使用方法。 步骤1 phpMyAdmin 介绍 phpmyadmin是一个用PHP编写的软件工具&#xff0c;可以通过web方式控制和操作MySQL数据库。通过phpMyAdmin可以完全对数据库进行…

目标检测:2如何生成自己的数据集

目录 1. 数据采集 2. 图像标注 3. 开源已标记数据集 4. 数据集划分 参考&#xff1a; 1. 数据采集 数据采集是深度学习和人工智能任务中至关重要的一步&#xff0c;它为模型提供了必要的训练样本和测试数据。在实际应用中&#xff0c;数据采集的方法多种多样&#xff0c;每…

Linux网络通信——TCP/OSI七层模型/TCP/IP(五层或四层模型)/HTTP报文传输原理

文章目录 消息的传输什么是OSI七层模型OSI七层模型的内容物理层&#xff08;Physical Layer&#xff09;&#xff1a;数据链路层&#xff08;Data Link Layer&#xff09;&#xff1a;网络层&#xff08;Network Layer&#xff09;&#xff1a;传输层&#xff08;Transport Lay…

Docker基础与持续集成

docker 基础知识&#xff1a; docker与虚拟机 !左边为虚拟机&#xff0c;右边为docker环境 – Server :物理机服务器Host OS &#xff1a;构建的操作系统Hypervisor &#xff1a;一种虚拟机软件&#xff0c;装了之后才能虚拟化操作系统Guest OS &#xff1a;虚拟化的操作系统…

操作系统-01-Mac 苹果操作系统 Brew /端口占用

Brew brew 又叫 Homebrew&#xff0c;是 Mac OSX上的软件包管理工具。类似 ubuntu 中的 apt-get。 Install $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"如下 houbinbindeMacBook-Pro:tools houbin…

机器学习系列——(十)支持向量机

一、背景 支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种用于分类、回归和离群点检测等领域的监督学习方法。它最初由Vapnik和Cortes在1995年提出&#xff0c;被认为是机器学习领域中最成功的算法之一。 二、原理 2.1 线性SVM 我们先从最简…

django+flask网上购物商城系统的设计与实现python-vue

全球经济在快速的发展&#xff0c;中国更是进步飞速&#xff0c;这使得国内的互联网技术进入了发展的高峰时期&#xff0c;这让中外资本不断转向互联网这个大市场[3]。在这个信息高度发达的现在&#xff0c;利用网络进行信息管理改革已经成为了人们追捧的一种趋势。“网上购物系…