網(wǎng)絡(luò)培訓(xùn)的網(wǎng)站建設(shè)注冊網(wǎng)站在哪里注冊
GO系列
1、GO學(xué)習(xí)之Hello World
2、GO學(xué)習(xí)之入門語法
3、GO學(xué)習(xí)之切片操作
4、GO學(xué)習(xí)之 Map 操作
5、GO學(xué)習(xí)之 結(jié)構(gòu)體 操作
6、GO學(xué)習(xí)之 通道(Channel)
7、GO學(xué)習(xí)之 多線程(goroutine)
8、GO學(xué)習(xí)之 函數(shù)(Function)
9、GO學(xué)習(xí)之 接口(Interface)
10、GO學(xué)習(xí)之 網(wǎng)絡(luò)通信(Net/Http)
11、GO學(xué)習(xí)之 微框架(Gin)
12、GO學(xué)習(xí)之 數(shù)據(jù)庫(mysql)
13、GO學(xué)習(xí)之 數(shù)據(jù)庫(Redis)
14、GO學(xué)習(xí)之 搜索引擎(ElasticSearch)
15、GO學(xué)習(xí)之 消息隊列(Kafka)
16、GO學(xué)習(xí)之 遠(yuǎn)程過程調(diào)用(RPC)
17、GO學(xué)習(xí)之 goroutine的調(diào)度原理
18、GO學(xué)習(xí)之 通道(nil Channel妙用)
19、GO學(xué)習(xí)之 同步操作sync包
20、GO學(xué)習(xí)之 互斥鎖、讀寫鎖該如何取舍
21、GO學(xué)習(xí)之 條件變量 sync.Cond
22、GO學(xué)習(xí)之 單例模式 sync.Once
文章目錄
- GO系列
- 前言
- sync.Once 如何使用
前言
按照公司目前的任務(wù),go 學(xué)習(xí)是必經(jīng)之路了,雖然行業(yè)卷,不過技多不壓身,依舊努力!!!
那sync.Once
又是什么呢?某個 goroutine 只需要且只能執(zhí)行一次,到目前為止我們知道程序運行期間只被執(zhí)行一次的就是每個包的 init
函數(shù),sync包也提供了這樣一種更靈活的機(jī)制,可以保證 任意一個函數(shù) 在程序運行期間只被執(zhí)行一次,就是 sync.Once了。
sync.Once 如何使用
在 JAVA 開發(fā)中,Spring 框架使用了 單例模式 來創(chuàng)建實體 Bean,我們在開發(fā)中也是多用單例模式來避免實例的重復(fù)創(chuàng)建。
在 Go 標(biāo)準(zhǔn)庫中,sync.Once 的 “僅僅執(zhí)行一次” 的特性被多用于初始化操作或者是資源清理的過程中,以避免重復(fù)執(zhí)行導(dǎo)致性能不是最佳。
sync.Once 的語義十分適合實現(xiàn)單例模式(singleton)模式,并且實現(xiàn)起來也和簡單,如下獲取實例的例子:
package mainimport ("log""sync""time"
)// 定義一個結(jié)構(gòu)體對象
type Entity struct{}var once sync.Once// 聲明一個接口實例,用于存放實例
var instance *Entityfunc 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 真正的執(zhí)行創(chuàng)建實體操作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.WaitGroupfor 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")
}
運行結(jié)果:
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
從運行結(jié)果中我們可以觀察到,sync.Do 會等待 func() 執(zhí)行完畢才返回,在這期間其他的執(zhí)行 once.Do 函數(shù)的 goroutine(如上述例子的 goroutine 1 ~ 4) 將會阻塞等待。
等 goroutine 5 的 sync.Do 執(zhí)行完后,其他的 goroutine 在調(diào)用 sync.Do 時將不再執(zhí)行里面的 func() 并立即返回(如 goroutine 0)。
我們還可以觀察到,即便在函數(shù) func() 中出現(xiàn) panic, sync.Once 依舊認(rèn)為 once.Do 執(zhí)行完畢,其他 goroutine 調(diào)用 once.Do 將不再執(zhí)行 func() 。
現(xiàn)階段還是對 Go 語言的學(xué)習(xí)階段,想必有一些地方考慮的不全面,本文示例全部是親自手敲代碼并且執(zhí)行通過。
如有問題,還請指教。
評論去告訴我哦!!!一起學(xué)習(xí)一起進(jìn)步!!!