Go語言并發(fā)編程 sync.Once
sync.Once
用于保證某個(gè)動(dòng)作只被執(zhí)行一次,可用于單例模式中,比如初始化配置。我們知道init()函數(shù)也只會(huì)執(zhí)行一次,不過它是在main()
函數(shù)之前執(zhí)行,如果想要在代碼執(zhí)行過程中只運(yùn)行某個(gè)動(dòng)作一次,可以使用sync.Once
,下面來介紹一下它的使用方法。
先來看下面的代碼:
package main import ( "fmt" "sync" ) func main() { var num = 6 var once sync.Once add_one := func() { num = num + 1 } minus_one := func() { num = num - 1 } once.Do(add_one) fmt.Printf("The num: %d\n", num) once.Do(minus_one) fmt.Printf("The num: %d\n", num) }
執(zhí)行結(jié)果:
The num: 7
The num: 7
sync.Once
類型提供了一個(gè)Do
方法,Do方法只接受一個(gè)參數(shù),且參數(shù)類型必須是func()
,也就是沒有參數(shù)聲明和結(jié)果聲明的函數(shù)。
Do
方法只會(huì)執(zhí)行首次被調(diào)用時(shí)傳入的那個(gè)函數(shù),只執(zhí)行一次,也不會(huì)執(zhí)行其它函數(shù)。上面的例子中,即使傳入的函數(shù)不同,也只會(huì)執(zhí)行第一次傳入的那個(gè)函數(shù)。如果有多個(gè)只執(zhí)行一次的函數(shù),需要為每一個(gè)函數(shù)分配一個(gè)sync.Once
類型的值:
func main() { var num = 6 var once1 sync.Once var once2 sync.Once add_one := func() { num = num + 1 } minus_one := func() { num = num - 1 } once1.Do(add_one) fmt.Printf("The num: %d\n", num) once2.Do(minus_one) fmt.Printf("The num: %d\n", num) }
sync.Once
類型是一個(gè)結(jié)構(gòu)體類型,一個(gè)是名為done
的uint32
類型字段,還有一個(gè)互斥鎖m
。
type Once struct { done uint32 m Mutex }
done
字段的值只可能是0或者1,Do
方法首次調(diào)用完成后,done
的值就變?yōu)榱?。done的值使用四個(gè)字節(jié)的uint32
類型的原因是為了保證對(duì)它的操作是“原子操作”,通過調(diào)用atomic.LoadUint32
函數(shù)獲取它的值,如果為1,直接返回,不會(huì)執(zhí)行函數(shù)。
如果為0,Do方法會(huì)立即鎖定字段m,如果這里不加鎖,多個(gè)goroutine
同時(shí)執(zhí)行到Do方法時(shí)判斷都為0,則都會(huì)執(zhí)行函數(shù),所以Once
是并發(fā)安全的。
加鎖之后,會(huì)再次檢查done
字段的值,如果滿足條件,執(zhí)行傳入的函數(shù),并用原子操作函數(shù)atomic.StoreUint32
將done
的值設(shè)置為1。
下面是Once的源碼:
func (o *Once) Do(f func()) { if atomic.LoadUint32(&o.done) == 0 { 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() } }
源碼非常簡潔,和GoF 設(shè)計(jì)模式中的單例模式非常相似。
到此這篇關(guān)于Go語言并發(fā)編程 sync.Once的文章就介紹到這了,更多相關(guān)Go語言 sync.Once內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Go語言標(biāo)準(zhǔn)庫sync.Once使用場景及性能優(yōu)化詳解
- golang使用sync.Once實(shí)現(xiàn)懶加載的用法和坑點(diǎn)詳解
- golang中sync.Once只執(zhí)行一次的原理解析
- Golang并發(fā)利器sync.Once的用法詳解
- go并發(fā)利器sync.Once使用示例詳解
- go?sync.Once實(shí)現(xiàn)高效單例模式詳解
- Golang基于sync.Once實(shí)現(xiàn)單例的操作代碼
- 一文解析 Golang sync.Once 用法及原理
- Go并發(fā)編程之sync.Once使用實(shí)例詳解
- 深入理解go sync.Once的具體使用
相關(guān)文章
深入了解Go的interface{}底層原理實(shí)現(xiàn)
本文主要介紹了Go的interface{}底層原理實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06go json編譯原理XJSON實(shí)現(xiàn)四則運(yùn)算
這篇文章主要為大家介紹了go json編譯原理XJSON實(shí)現(xiàn)四則運(yùn)算示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Golang 端口復(fù)用測試的實(shí)現(xiàn)
這篇文章主要介紹了Golang 端口復(fù)用測試的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Go使用協(xié)程批量獲取數(shù)據(jù)加快接口返回速度
這篇文章主要介紹了Go使用協(xié)程批量獲取數(shù)據(jù)加快接口返回速度,使用Go語言后,可以并發(fā)獲取,極大提升效率,需要的朋友可以參考下2023-02-02