Sync.Map 和 map 有什么区别?
Sync.Map 和 map 有什么区别?
提示
题眼: 并发安全。
普通 map 不支持并发读写安全,sync.Map 支持并发安全。sync.Map 使用了读写分离的思路,通过互斥锁和原子操作配合来提升并发场景下的读写效率。其核心结构如下:
type Map struct {
mu Mutex
read atomic.Value // 本质上存的是 readOnly 结构体
dirty map[interface{}]*entry
misses int // 统计未命中的次数
}
type readOnly struct {
m map[interface{}]*entry
amended bool // dirty 中是否包含 read 中没有的数据
}
type entry struct {
p unsafe.Pointer // 指向 interface{} 的指针
}从本质上说,sync.Map 的核心思想是“读多写少时尽量无锁读取”。大量读操作可以直接走只读区域,无需加锁;写入、删除和数据提升则在必要时才走加锁路径。
重要
参考答案:
普通 map 在 Go 里不是并发安全的,多个 goroutine 同时读写普通 map,很容易直接触发运行时错误。sync.Map 则是标准库提供的并发安全 Map。
它的底层没有简单地给 map 外面套一把大锁,而是做了读写分离。读请求优先走只读区域,大部分情况下可以无锁完成;写请求才会进入加锁路径,并在一定条件下把 dirty 数据提升到只读区。所以它在“读远多于写”的场景下性能通常不错。
sync.Map 比较适合配置缓存、只初始化一次后大量读取的数据,或者不同 goroutine 对不同 key 操作较分散的场景。但如果你的业务是强类型、写入频繁、还需要复杂遍历和类型约束,很多时候自己配合 map + RWMutex 会更直观。
另外,sync.Map 的 key 仍然必须是可比较类型,切片、map、函数等仍然不能作为 key。
