go中普通map和sync.map的區(qū)別小結(jié)
1. 普通map的特點(diǎn)
Go 內(nèi)置的 map 是非并發(fā)安全的:
- 在單協(xié)程里讀寫沒問題;
- 多協(xié)程同時(shí)寫會(huì)觸發(fā)
fatal error: concurrent map writes; - 多協(xié)程并發(fā)讀寫需要自己加鎖(如
sync.RWMutex)。
源碼層面(runtime/map.go):
map內(nèi)部通過hmap結(jié)構(gòu)體存儲(chǔ)桶(buckets)管理數(shù)據(jù);- 設(shè)計(jì)目標(biāo)是高性能單線程;
- 并沒有加鎖邏輯。
2.sync.Map的特點(diǎn)
Go 在 1.9+ 引入了 sync.Map,為高并發(fā)場景做了專門優(yōu)化。
特點(diǎn):
- 并發(fā)安全,內(nèi)部已經(jīng)封裝了鎖;
- 針對讀多寫少的場景做了特別優(yōu)化(類似“讀寫分離”)。
源碼層面(sync/map.go):
type Map struct {
mu Mutex // 寫操作用的鎖
read atomic.Value // 存儲(chǔ)只讀部分,原子讀
dirty map[any]*entry // 可寫部分,寫時(shí)更新
misses int // 記錄從 read 讀取失敗的次數(shù)
}
核心機(jī)制:
雙 map 設(shè)計(jì):
read(只讀,atomic.Value):無鎖讀,性能高;dirty(寫緩沖,受鎖保護(hù)):存儲(chǔ)新增/修改的數(shù)據(jù);
寫時(shí)遷移策略:當(dāng)
read中 miss 次數(shù)過多,會(huì)把dirty提升為read;保證讀快寫慢的同時(shí),整體高并發(fā)安全。
通過read和dirty
分別存儲(chǔ)讀寫狀態(tài),以空間換時(shí)間的策略,去減少鎖沖突。
3. 舉個(gè)對比例子
// 普通 map + 鎖
var m = make(map[string]int)
var mu sync.RWMutex
func safeWrite(k string, v int) {
mu.Lock()
defer mu.Unlock()
m[k] = v
}
func safeRead(k string) (int, bool) {
mu.RLock()
defer mu.RUnlock()
v, ok := m[k]
return v, ok
}
和 sync.Map 相比:
- 普通
map+RWMutex:寫性能更好,適合頻繁寫; sync.Map:讀性能更好,適合讀多寫少。
4. 面試回答
普通 map 是非并發(fā)安全的,需要開發(fā)者手動(dòng)用 sync.RWMutex 保證線程安全。
sync.Map 內(nèi)部采用 讀寫分離(read + dirty) 的雙 map 設(shè)計(jì),讀操作可以無鎖原子讀,寫操作用鎖保護(hù),并在一定 miss 次數(shù)后把 dirty 提升為 read。
適用場景不同:
sync.Map:讀多寫少,典型場景如緩存、配置表;map+RWMutex:寫多的場景更優(yōu)。
到此這篇關(guān)于go中普通map和sync.map的區(qū)別小結(jié)的文章就介紹到這了,更多相關(guān)go中普通map和sync.map內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go判斷文件夾是否存在并創(chuàng)建的實(shí)例
這篇文章主要介紹了go判斷文件夾是否存在,并創(chuàng)建的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
go內(nèi)存緩存如何new一個(gè)bigcache對象示例詳解
這篇文章主要為大家介紹了go內(nèi)存緩存如何new一個(gè)bigcache對象示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Go調(diào)度器學(xué)習(xí)之協(xié)作與搶占詳解
如果某個(gè)G執(zhí)行時(shí)間過長,其他的G如何才能被正常調(diào)度,這就引出了接下來的話題:協(xié)作與搶占。本文將通過一些示例為大家詳細(xì)講講調(diào)度器中協(xié)作與搶占的相關(guān)知識,需要的可以參考一下2023-04-04
Go語言fmt.Sprintf格式化輸出的語法與實(shí)例
Go 可以使用 fmt.Sprintf 來格式化字符串,下面這篇文章主要給大家介紹了關(guān)于Go語言fmt.Sprintf格式化輸出的語法與實(shí)例,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07

