go中普通map和sync.map的區(qū)別小結(jié)
1. 普通map的特點
Go 內(nèi)置的 map 是非并發(fā)安全的:
- 在單協(xié)程里讀寫沒問題;
- 多協(xié)程同時寫會觸發(fā)
fatal error: concurrent map writes; - 多協(xié)程并發(fā)讀寫需要自己加鎖(如
sync.RWMutex)。
源碼層面(runtime/map.go):
map內(nèi)部通過hmap結(jié)構(gòu)體存儲桶(buckets)管理數(shù)據(jù);- 設(shè)計目標是高性能單線程;
- 并沒有加鎖邏輯。
2.sync.Map的特點
Go 在 1.9+ 引入了 sync.Map,為高并發(fā)場景做了專門優(yōu)化。
特點:
- 并發(fā)安全,內(nèi)部已經(jīng)封裝了鎖;
- 針對讀多寫少的場景做了特別優(yōu)化(類似“讀寫分離”)。
源碼層面(sync/map.go):
type Map struct {
mu Mutex // 寫操作用的鎖
read atomic.Value // 存儲只讀部分,原子讀
dirty map[any]*entry // 可寫部分,寫時更新
misses int // 記錄從 read 讀取失敗的次數(shù)
}
核心機制:
雙 map 設(shè)計:
read(只讀,atomic.Value):無鎖讀,性能高;dirty(寫緩沖,受鎖保護):存儲新增/修改的數(shù)據(jù);
寫時遷移策略:當
read中 miss 次數(shù)過多,會把dirty提升為read;保證讀快寫慢的同時,整體高并發(fā)安全。
通過read和dirty
分別存儲讀寫狀態(tài),以空間換時間的策略,去減少鎖沖突。
3. 舉個對比例子
// 普通 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ā)者手動用 sync.RWMutex 保證線程安全。
sync.Map 內(nèi)部采用 讀寫分離(read + dirty) 的雙 map 設(shè)計,讀操作可以無鎖原子讀,寫操作用鎖保護,并在一定 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內(nèi)存緩存如何new一個bigcache對象示例詳解
這篇文章主要為大家介紹了go內(nèi)存緩存如何new一個bigcache對象示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09

