关于高并发下map结构不稳定的问题
更新中。。。
由于map为引用类型,就算经过函数传递参数,其副本依然指向映射m。当多个go协程并发改写同一个内存中的变量时,就会产生冲突,共享资源会被破坏。
注意:在单协程读写map里面的内容时,却不会发生冲突,所以为了并发安全,往往需要对map进行简单封装,给map上锁。
type CustomIntMap struct {
sync.RWMutex
internal map[string]int
}
func NewCustomIntMap() *CustomIntMap {
return &CustomIntMap{
internal: make(map[string]int),
}
}
func (rm *CustomIntMap) Load(key string) (value int, ok bool) {
rm.RLock()
result, ok := rm.internal[key]
rm.RUnlock()
return result, ok
}
func (rm *CustomIntMap) Delete(key string) {
rm.Lock()
delete(rm.internal, key)
rm.Unlock()
}
func (rm *CustomIntMap) Store(key string, value int) {
rm.Lock()
rm.internal[key] = value
rm.Unlock()
但是,加锁虽然安全但是也影响了运行的速度和读取性能。
为此go语言开发人员推出了sync.Map,它填补了Map线程不安全的缺陷,不过最好只在需要的情况下使用。它提供给用户使用的并发安全锁机制,实现上通过两个map结构,其中一个只读的map,另外一个通过RWLocker锁保护的读写map组成。适合仅新增key的情况,且读取数据的比例远大于更新数据的总量。它解决了多CPU更新同一个缓存变量的情况下,导致对于一个O(1)操作,在多个核心(N核)同时操作的时候,可能导致变为O(N)的操作的问题
关于Sync.Map的使用
值得一提的是无论是经过简单封装的map还是sync.Map,其性能都不如原生map,但是这也是没办法的事