go中普通map和sync.map的区别小结
作者:{⌐■_■}
本文主要介绍了go中普通map和sync.map的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
1. 普通map的特点
Go 内置的 map 是非并发安全的:
- 在单协程里读写没问题;
- 多协程同时写会触发
fatal error: concurrent map writes; - 多协程并发读写需要自己加锁(如
sync.RWMutex)。
源码层面(runtime/map.go):
map内部通过hmap结构体存储桶(buckets)管理数据;- 设计目标是高性能单线程;
- 并没有加锁逻辑。
2.sync.Map的特点
Go 在 1.9+ 引入了 sync.Map,为高并发场景做了专门优化。
特点:
- 并发安全,内部已经封装了锁;
- 针对读多写少的场景做了特别优化(类似“读写分离”)。
源码层面(sync/map.go):
type Map struct {
mu Mutex // 写操作用的锁
read atomic.Value // 存储只读部分,原子读
dirty map[any]*entry // 可写部分,写时更新
misses int // 记录从 read 读取失败的次数
}
核心机制:
双 map 设计:
read(只读,atomic.Value):无锁读,性能高;dirty(写缓冲,受锁保护):存储新增/修改的数据;
写时迁移策略:当
read中 miss 次数过多,会把dirty提升为read;保证读快写慢的同时,整体高并发安全。
通过read和dirty
分别存储读写状态,以空间换时间的策略,去减少锁冲突。
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 是非并发安全的,需要开发者手动用 sync.RWMutex 保证线程安全。
sync.Map 内部采用 读写分离(read + dirty) 的双 map 设计,读操作可以无锁原子读,写操作用锁保护,并在一定 miss 次数后把 dirty 提升为 read。
适用场景不同:
sync.Map:读多写少,典型场景如缓存、配置表;map+RWMutex:写多的场景更优。
到此这篇关于go中普通map和sync.map的区别小结的文章就介绍到这了,更多相关go中普通map和sync.map内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
