GoLang中的sync包Once使用執(zhí)行示例
背景
在系統(tǒng)初始化的時候,某些代碼只想被執(zhí)行一次,這時應該怎么做呢,沒有學習 Once 前,大家可能想到 聲明一個標識,表示是否初始化過,然后初始化這個標識加鎖,更新這個標識。
但是學會了 One 的使用可以更加簡單的解決這個問題
One簡介
Once 包主要用于在并發(fā)執(zhí)行代碼的時候,某部分代碼只會被執(zhí)行 一次。
Once 的使用也非常簡單,Once 只有一個 Do 方法,接收一個無參數無返回值的函數類型的參數 f,不管調用多少次 Do 方法,參數 f 只在第一次調用 Do 方法時執(zhí)行。
示例
我們有一個Msg 參數,多個協(xié)程都會用到他,但是這個參數只用初始化一次就可以。
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 執(zhí)行初始化!\n", i)
msg = "Your Need Data"
})
fmt.Println(msg)
}(i)
}
time.Sleep(3* time.Second)
}
執(zhí)行結果如下:

可以看到初始化的代碼只被4號線程執(zhí)行了一次, 其他協(xié)程都是直接讀的初始化的數據,并沒有執(zhí)行初始化的函數。
注意
不要在 Do() 方法的參數方法中再次調用Do() 方法,因為執(zhí)行這個Do() 方法的參數方法的時候,One 會持有一個鎖,如果再參數方法中再次調用Do() 方法,就會等待這個鎖釋放, 導致參數方法無法執(zhí)行完畢,然后外層的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")
}
執(zhí)行結果:

可以知道再 fun1() 中使用 Do() 方法調用 fun2 的時候形成了死鎖, 因為在 fun1() 執(zhí)行過程中已將持有了該鎖,需要 fun1() 執(zhí)行完畢才會釋放,然后因為使用 Do() 方法執(zhí)行 fun2() 也會請求這個鎖, 會一直等待,導致 fun1() 不可能執(zhí)行完, 也不可能釋放鎖。成了死鎖。
源碼解讀
查看源碼
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()
}
}
使用一個原子類作為標識,加鎖校驗和操作原子類,保證只會被一個協(xié)程執(zhí)行。
Do 調用了 doSlow , 在 doSlow 中有defer 關鍵字,表示執(zhí)行函數和釋放鎖是倒序執(zhí)行,必須先執(zhí)行完畢 if 判斷和里面的 f() 才能釋放鎖。
到此這篇關于GoLang中的sync包Once使用執(zhí)行示例的文章就介紹到這了,更多相關Go sync Once內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang實現(xiàn)數據結構Stack(堆棧)的示例詳解
在計算機科學中,stack(棧)是一種基本的數據結構,它是一種線性結構,具有后進先出(Last In First Out)的特點。本文將通過Golang實現(xiàn)堆棧,需要的可以參考一下2023-04-04
golang獲取當前時間、時間戳和時間字符串及它們之間的相互轉換方法
這篇文章主要介紹了golang獲取當前時間、時間戳和時間字符串及它們之間的相互轉換,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友一起看看吧2025-04-04
go語言規(guī)范RESTful?API業(yè)務錯誤處理
這篇文章主要為大家介紹了go語言規(guī)范RESTful?API業(yè)務錯誤處理方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03

