sync.Once保证运行期间的某段代码只会执行一次

2023年 9月 16日 57.6k 0

初入门径

sync.Once提供了保证某个操作只被执行一次的功能,其最常应用于单例模式之下,例如初始化系统配置、保持数据库唯一连接,以及并发访问只需要初始化一次的共享资源。

单例模式有懒汉模式和饿汉模式两种

饿汉模式 顾名思义就是比较饥饿,所以一上来(服务启动时)就初始化。 懒汉模式 顾名思义就是偷懒,在获取实例的时候在进行初始化,但懒汉模式会有并发问题:有可能多个 goruntine 同时获取 对象都是 nil ,然后都开始创建了实例,就不满足单例模式了。解决办法是加锁

sync.Once就是懒汉模式

Go并发编程 — sync.Once

package main

import (
	"fmt"
	"sync"
)

func main() {
	var once sync.Once
	fun1 := func() {
		fmt.Println("一只老虎")
	}
	once.Do(fun1)

	fun2 := func() {
		fmt.Println("两只老虎")
	}

	once.Do(fun2)
}

输出为:

一只老虎

并发调用 Do()

package main

import (
	"fmt"
	"sync"
	"time"
)

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)
	}

	// 为防止主goroutine直接运行完,什么都看不到
	time.Sleep(50 * time.Millisecond)
}

在上面这段代码里,开启了5个并发的 goroutine ,不管执行多少次, 始终只打印一次. 至于 i 是多少,就看先执行的是哪个 g 了。

Once 保证只有第一次调用 Do() 方法时, 传递的 f (无参数无返回值的函数) 才会执行,并且之后不管调用的参数是否改变了,也不管f执行时是否发生了panic,之后都不再执行。

这段是官方Demo:

 package main

import (
"fmt"
"sync"
)

func main() {
var once sync.Once
onceBody := func() {
fmt.Println("Only once")
}
done := make(chan bool)
for i := 0; i < 10; i++ {
go func() {
once.Do(onceBody)
done

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论