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

