GoLang中的sync包Once使用执行示例

 更新时间:2023年03月06日 10:43:57   作者:水淹萌龙  
这篇文章主要介绍了GoLang中的sync包Once使用执行示例,没有学习Once前,大家可能想到 声明一个标识,表示是否初始化过,然后初始化这个标识加锁,更新这个标识,Once包主要用于在并发执行代码的时候,某部分代码只会被执行一次

背景

在系统初始化的时候,某些代码只想被执行一次,这时应该怎么做呢,没有学习 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() 才能释放锁。

到此这篇关于GoLang中的sync包Once使用执行示例的文章就介绍到这了,更多相关Go sync Once内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go框架三件套Gorm Kitex Hertz基本用法与常见API讲解

    Go框架三件套Gorm Kitex Hertz基本用法与常见API讲解

    这篇文章主要为大家介绍了Go框架三件套Gorm Kitex Hertz的基本用法与常见API讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2023-02-02
  • Golang算法问题之数组按指定规则排序的方法分析

    Golang算法问题之数组按指定规则排序的方法分析

    这篇文章主要介绍了Golang算法问题之数组按指定规则排序的方法,结合实例形式分析了Go语言数组排序相关算法原理与操作技巧,需要的朋友可以参考下
    2017-02-02
  • go gin+token(JWT)验证实现登陆验证

    go gin+token(JWT)验证实现登陆验证

    本文主要介绍了go gin+token(JWT)验证实现登陆验证,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • golang时间字符串和时间戳转换的案例

    golang时间字符串和时间戳转换的案例

    这篇文章主要介绍了golang时间字符串和时间戳转换的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • win10下go mod配置方式

    win10下go mod配置方式

    这篇文章主要介绍了win10下go mod配置方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • 如何使用工具自动监测SSL证书有效期并发送提醒邮件

    如何使用工具自动监测SSL证书有效期并发送提醒邮件

    本文介绍了如何开发一个工具,用于每日检测SSL证书剩余有效天数并通过邮件发送提醒,工具基于命令行,通过SMTP协议发送邮件,需配置SMTP连接信息,本文还提供了配置文件样例及代码实现,帮助用户轻松部署和使用该工具
    2024-10-10
  • 一文秒懂Go 编写命令行工具的代码

    一文秒懂Go 编写命令行工具的代码

    这篇文章主要介绍了一文秒懂Go 编写命令行工具的代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • 使用Go实现邮箱验证码API功能

    使用Go实现邮箱验证码API功能

    本文将带你了解一个项目如何实现一个邮箱验证接口,即一个可用的发送邮箱验证码API和验证验证码是否正确功能,对Go实现邮箱验证码API详细过程感兴趣的朋友一起看看吧
    2024-06-06
  • 如何使用Golang创建与读取Excel文件

    如何使用Golang创建与读取Excel文件

    我最近工作忙于作图,图表,需要自己准备数据源,所以经常和Excel打交道,下面这篇文章主要给大家介绍了关于如何使用Golang创建与读取Excel文件的相关资料,需要的朋友可以参考下
    2022-07-07
  • Go语言学习之context包的用法详解

    Go语言学习之context包的用法详解

    日常Go开发中,Context包是用的最多的一个了,几乎所有函数的第一个参数都是ctx,那么我们为什么要传递Context呢,Context又有哪些用法,底层实现是如何呢?相信你也一定会有探索的欲望,那么就跟着本篇文章,一起来学习吧
    2022-10-10

最新评论