Go語言優(yōu)雅實(shí)現(xiàn)單例模式的多種方式
單例模式的基本定義
單例模式(Singleton Pattern)是一種設(shè)計(jì)模式,旨在保證一個(gè)類只有一個(gè)實(shí)例,并且提供全局訪問點(diǎn)。單例模式通常用于需要限制某個(gè)對(duì)象的實(shí)例數(shù)量為一個(gè)的場(chǎng)景,比如數(shù)據(jù)庫(kù)連接池、日志管理器、配置管理器等。
Go語言單例模式的實(shí)現(xiàn)
1. 線程安全的懶漢式單例
懶漢式的實(shí)現(xiàn)會(huì)延遲實(shí)例的創(chuàng)建,直到第一次調(diào)用時(shí)才會(huì)實(shí)例化對(duì)象。為了保證并發(fā)情況下的安全性,我們需要使用 sync.Once
來確保實(shí)例只會(huì)創(chuàng)建一次。
package main import ( "fmt" "sync" ) var wg sync.WaitGroup // Singleton 類型 type Singleton struct { } var instance *Singleton var once sync.Once // GetInstance 提供全局唯一的實(shí)例 func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{} }) return instance } func main() { // 獲取單例實(shí)例 for i := 0; i < 10; i++ { wg.Add(1) go func(index int) { defer wg.Done() s1 := GetInstance() fmt.Printf("index %d, memery address: %p\n", index, s1) }(i) } wg.Wait() }
結(jié)果
index 0, memery address: 0x56c480
index 5, memery address: 0x56c480
index 4, memery address: 0x56c480
index 2, memery address: 0x56c480
index 7, memery address: 0x56c480
index 9, memery address: 0x56c480
index 6, memery address: 0x56c480
index 8, memery address: 0x56c480
index 3, memery address: 0x56c480
index 1, memery address: 0x56c480
解析:
sync.Once
:Go標(biāo)準(zhǔn)庫(kù)提供的一個(gè)同步原語,確保某個(gè)函數(shù)只會(huì)被調(diào)用一次。它在并發(fā)情況下保證了線程安全。once.Do
:此方法確保傳入的函數(shù)只執(zhí)行一次,適用于懶加載單例實(shí)例。
2. 雙重檢查鎖定(DCL)
雙重檢查鎖定是一種優(yōu)化方式,它通過在兩次檢查實(shí)例時(shí),減少了加鎖的開銷,提高了性能。
package main import ( "fmt" "sync" ) var wg sync.WaitGroup // Singleton 類型 type Singleton struct { } var instance *Singleton var lock sync.Mutex func GetInstance() *Singleton { if instance == nil { lock.Lock() defer lock.Unlock() if instance == nil { instance = &Singleton{} } } return instance } func main() { // 獲取單例實(shí)例 for i := 0; i < 10; i++ { wg.Add(1) go func(index int) { defer wg.Done() s1 := GetInstance() fmt.Printf("index %d, memery address: %p\n", index, s1) }(i) } wg.Wait() }
解析:
- 雙重檢查:第一次檢查實(shí)例是否為
nil
,如果是,則加鎖。然后再次檢查實(shí)例是否為nil
,如果是則創(chuàng)建實(shí)例。 - 鎖的優(yōu)化:只有在實(shí)例尚未創(chuàng)建時(shí)才會(huì)加鎖,避免了每次獲取實(shí)例時(shí)都需要加鎖的性能損耗。
3. 原子操作法
Go 語言的 sync/atomic
包提供了原子操作,我們可以利用它來確保單例的線程安全。
package main import ( "fmt" "sync" "sync/atomic" "unsafe" ) var wg sync.WaitGroup type Singleton struct { } var instance unsafe.Pointer func GetInstance() *Singleton { // 使用原子操作獲取實(shí)例 if atomic.LoadPointer(&instance) == nil { newInstance := &Singleton{} atomic.StorePointer(&instance, unsafe.Pointer(newInstance)) } return (*Singleton)(atomic.LoadPointer(&instance)) } func main() { // 獲取單例實(shí)例 for i := 0; i < 10; i++ { wg.Add(1) go func(index int) { defer wg.Done() s1 := GetInstance() fmt.Printf("index %d, memery address: %p\n", index, s1) }(i) } wg.Wait() }
解析:
unsafe.Pointer
:在Go中,unsafe.Pointer
可以用來繞過類型系統(tǒng),直接處理內(nèi)存地址。通過原子操作確保實(shí)例賦值的安全性。atomic.LoadPointer
和atomic.StorePointer
:原子加載和存儲(chǔ)指針,確保操作的線程安全性。
總結(jié)
在Go語言中實(shí)現(xiàn)單例模式有多種方式,最常見的是使用 sync.Once
、雙重檢查鎖定(DCL)和原子操作法。每種方法有其優(yōu)缺點(diǎn),選擇合適的方式可以幫助你在保證線程安全的前提下優(yōu)化性能。
到此這篇關(guān)于Go語言優(yōu)雅實(shí)現(xiàn)單例模式的多種方式的文章就介紹到這了,更多相關(guān)Go實(shí)現(xiàn)單例模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
讓go程序以后臺(tái)進(jìn)程或daemon方式運(yùn)行方法探究
本文探討了如何通過Go代碼實(shí)現(xiàn)在后臺(tái)運(yùn)行的程序,最近我用Go語言開發(fā)了一個(gè)WebSocket服務(wù),我希望它能在后臺(tái)運(yùn)行,并在異常退出時(shí)自動(dòng)重新啟動(dòng),我的整體思路是將程序轉(zhuǎn)為后臺(tái)進(jìn)程,也就是守護(hù)進(jìn)程(daemon)2024-01-01基于go手動(dòng)寫個(gè)轉(zhuǎn)發(fā)代理服務(wù)的代碼實(shí)現(xiàn)
這篇文章主要介紹了基于go手動(dòng)寫個(gè)轉(zhuǎn)發(fā)代理服務(wù)的代碼實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02一文搞懂Go語言標(biāo)準(zhǔn)庫(kù)strconv
strconv包實(shí)現(xiàn)了基本數(shù)據(jù)類型和其字符串表示的相互轉(zhuǎn)換,本文主要介紹Go語言標(biāo)準(zhǔn)庫(kù)strconv,想要學(xué)習(xí)strconv標(biāo)準(zhǔn)庫(kù)的可以了解一下2023-04-04VSCode1.4 搭建Golang的開發(fā)調(diào)試環(huán)境(遇到很多問題)
這篇文章主要介紹了VSCode1.4 搭建Golang的開發(fā)調(diào)試環(huán)境(遇到很多問題),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04一文教你如何快速學(xué)會(huì)Go的struct數(shù)據(jù)類型
結(jié)構(gòu)是表示字段集合的用戶定義類型。它可以用于將數(shù)據(jù)分組為單個(gè)單元而不是將每個(gè)數(shù)據(jù)作為單獨(dú)的值的地方。本文就來和大家聊聊Go中struct數(shù)據(jù)類型的使用,需要的可以參考一下2023-03-03Go語言調(diào)用ffmpeg-api實(shí)現(xiàn)音頻重采樣
最近對(duì)golang處理音視頻很感興趣,對(duì)golang音視頻常用庫(kù)goav進(jìn)行了一番研究。自己寫了一個(gè)wav轉(zhuǎn)采樣率的功能。給大家分享一下,中間遇到了不少坑,解決的過程中還是蠻有意思的,希望大家能喜歡2022-12-12