GO学习之 单例模式 sync.Once

GO系列

1、GO学习之Hello World

2、GO学习之入门语法

3、GO学习之切片操作

4、GO学习之 Map 操作

5、GO学习之 结构体 操作

6、GO学习之 通道(Channel)

7、GO学习之 多线程(goroutine)

8、GO学习之 函数(Function)

9、GO学习之 接口(Interface)

10、GO学习之 网络通信(Net/Http)

11、GO学习之 微框架(Gin)

12、GO学习之 数据库(mysql)

13、GO学习之 数据库(Redis)

14、GO学习之 搜索引擎(ElasticSearch)

15、GO学习之 消息队列(Kafka)

16、GO学习之 远程过程调用(RPC)

17、GO学习之 goroutine的调度原理

18、GO学习之 通道(nil Channel妙用)

19、GO学习之 同步操作sync包

20、GO学习之 互斥锁、读写锁该如何取舍

21、GO学习之 条件变量 sync.Cond

22、GO学习之 单例模式 sync.Once

文章目录

前言

按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!

sync.Once又是什么呢?某个 goroutine 只需要且只能执行一次,到目前为止我们知道程序运行期间只被执行一次的就是每个包的 init 函数,sync包也提供了这样一种更灵活的机制,可以保证 任意一个函数 在程序运行期间只被执行一次,就是 sync.Once了。

sync.Once 如何使用

在 JAVA 开发中,Spring 框架使用了 单例模式 来创建实体 Bean,我们在开发中也是多用单例模式来避免实例的重复创建。

在 Go 标准库中,sync.Once 的 "仅仅执行一次" 的特性被多用于初始化操作或者是资源清理的过程中,以避免重复执行导致性能不是最佳。

sync.Once 的语义十分适合实现单例模式(singleton)模式,并且实现起来也和简单,如下获取实例的例子:

go 复制代码
package main

import (
	"log"
	"sync"
	"time"
)

// 定义一个结构体对象
type Entity struct{}

var once sync.Once

// 声明一个接口实例,用于存放实例
var instance *Entity

func GetFun(id int) *Entity {
	// 延迟获取异常信息
	defer func() {
		e := recover()
		if e != nil {
			log.Printf("goroutine %d catch a panic: %s \n", id, e)
		}
	}()
	log.Printf("goroutine %d start run... \n", id)
	// once.Do 真正的执行创建实体操作
	once.Do(func() {
		instance = &Entity{}
		time.Sleep(3 * time.Second)
		log.Printf("goroutine %d create instance : %p\n", id, instance)
		panic("success to create a instance")
	})
	return instance
}

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func(i int) {
			inst := GetFun(i)
			log.Printf("goroutine %d get a instance: %p", i, inst)
			wg.Done()
		}(i + 1)
	}
	time.Sleep(5 * time.Second)
	inst := GetFun(0)
	log.Printf("goroutine %d get a instance: %p", 0, inst)
	wg.Wait()
	log.Printf("all goroutine done \n")
}

运行结果:

bash 复制代码
PS D:\workspaceGo\src\sync> go run .\sync_once_main.go
2023/12/02 16:17:04 goroutine 5 start run... 
2023/12/02 16:17:04 goroutine 2 start run...
2023/12/02 16:17:04 goroutine 1 start run...
2023/12/02 16:17:04 goroutine 3 start run...
2023/12/02 16:17:04 goroutine 4 start run...
2023/12/02 16:17:07 goroutine 5 create instance : 0xa477c0
2023/12/02 16:17:07 goroutine 5 catch a panic: success to create a instance
2023/12/02 16:17:07 goroutine 5 get a instance: 0x0
2023/12/02 16:17:07 goroutine 3 get a instance: 0xa477c0
2023/12/02 16:17:07 goroutine 2 get a instance: 0xa477c0
2023/12/02 16:17:07 goroutine 4 get a instance: 0xa477c0
2023/12/02 16:17:07 goroutine 1 get a instance: 0xa477c0
2023/12/02 16:17:09 goroutine 0 start run... 
2023/12/02 16:17:09 goroutine 0 get a instance: 0xa477c0
2023/12/02 16:17:09 all goroutine done

从运行结果中我们可以观察到,sync.Do 会等待 func() 执行完毕才返回,在这期间其他的执行 once.Do 函数的 goroutine(如上述例子的 goroutine 1 ~ 4) 将会阻塞等待。

等 goroutine 5 的 sync.Do 执行完后,其他的 goroutine 在调用 sync.Do 时将不再执行里面的 func() 并立即返回(如 goroutine 0)。

我们还可以观察到,即便在函数 func() 中出现 panic, sync.Once 依旧认为 once.Do 执行完毕,其他 goroutine 调用 once.Do 将不再执行 func() 。


现阶段还是对 Go 语言的学习阶段,想必有一些地方考虑的不全面,本文示例全部是亲自手敲代码并且执行通过。
如有问题,还请指教。

评论去告诉我哦!!!一起学习一起进步!!!

相关推荐
IT=>小脑虎8 小时前
Go语言零基础小白学习知识点【基础版详解】
开发语言·后端·学习·golang
源代码•宸8 小时前
Golang语法进阶(并发概述、Goroutine、Channel)
服务器·开发语言·后端·算法·golang·channel·goroutine
WayneJoon.H9 小时前
2023CISCN go_session
网络安全·golang·ctf·代码审计·ciscn
-曾牛10 小时前
Yak语言核心基础:语句、变量与表达式详解
数据库·python·网络安全·golang·渗透测试·安全开发·yak
源代码•宸18 小时前
Leetcode—1123. 最深叶节点的最近公共祖先【中等】
经验分享·算法·leetcode·职场和发展·golang·dfs
源代码•宸18 小时前
Golang基础语法(go语言error、go语言defer、go语言异常捕获、依赖管理、Go Modules命令)
开发语言·数据库·后端·算法·golang·defer·recover
-曾牛19 小时前
Yak:专注安全能力融合的编程语言快速入门
安全·网络安全·golang·渗透测试·编程语言·yakit·yak
bruce_哈哈哈19 小时前
go语言初认识
开发语言·后端·golang
moxiaoran575319 小时前
Go语言的接口
开发语言·后端·golang
源代码•宸19 小时前
Leetcode—865. 具有所有最深节点的最小子树【中等】
开发语言·经验分享·后端·算法·leetcode·golang·dfs