sync.Map简述
简单来说,sync.Map是并发版本的map,golang自带的map在并发操作下会触发panic。sync.Map支持Load,Store, LoadOrStore,Range,Delete操作。其中Range支持在多goroutine下运作,能确保每个key最多被处理一次,但是无法保证遍历过程中实时同步其他goroutine的增删操作。
使用sync.Map
你真的需要sync.Map吗?
比起sync.Map如何使用,一个更重要的问题在于我们是否真的需要sync.Map。的确如我们之前所说,sync.Map支持并发而map不支持,但是我们可以很轻松的用RWMutex或者Mutex结合map来支持并发,而且比起sync.Map,这两种方案更好的支持类型安全,而且在绝大多数时候性能更优。一个简单的答案是,如果你不知道为什么需要sync.Map,那么很可能你不需要sync.Map。
那么什么时候我们需要sync.Map呢?要解答这个问题,我们不妨回顾下sync.Map被提出的原因。简单来说,sync.Map被提出是因为google发现,RWLock配合map方案在高读取+多核cpu上表现不佳(具体可以翻看overview of sync map)。因此,snyc.Map就是为了改善多核高读取低写入时候的性能而引入。
具体来说,如果你的应用有以下的属性,那么可以考虑使用,否则更加建议使用RWMutex或者Mutex结合map的方案
- 如果写入的key是稳定的(极少)
- 如果不同goroutine对key的访问是不同的
如何更好地使用sync.Map
sync.Map有着非常简单的API,如果你需要存储新的键值对,你可以使用Store,如果你需要读取键值对,你可以使用Load;如果需要删除某个键值对,那么使用Delete;如果你需要遍历整个map,Range在那里等你。
但是我们如果观察sync.Map的API,我们会发现,为了考虑通用性,所有的key和value都是interface{},换言之,我们失去了类型检查提供的安全性而且被迫更多的使用类型断言。于是你面临着两种选择:在每次调用API后都小心翼翼地使用类型断言,你的代码里面出现无数的if v,ok=value.(xxType);!ok{};亦或者每一次都直接使用v.(xxType)直到你的进程在某些关键时刻宕机让你抓耳挠腮为止。那么我们还有第三种方案吗?庆幸的是,答案是有的,不过需要我们做出一些小小的努力。
如果你的map在使用的时候有明确类型,一个简单的思路是封装snyc.Map并且对外提供指定类型的Load,Delete、Store等等
type StringMap struct{
m sync.Map
}
func (s *StringMap) Store(key,value string){
s.m.Store

本文详细介绍了Golang中的sync.Map,它是一个并发安全的Map。文章讨论了何时需要使用sync.Map,如何正确使用,以及它的实现原理,包括read和dirty两个内部map的运作方式。还提到了sync.Map的一些使用细节,如Range方法和kv类型的选择,并提醒开发者在不满足特定场景时,常规的并发控制方式可能是更好的选择。
最低0.47元/天 解锁文章

2136

被折叠的 条评论
为什么被折叠?



