Golang:sync.Map
发布时间:2020-12-16 09:31:23 所属栏目:大数据 来源:网络整理
导读:由于map在gorountine 上不是安全的,所以在大量并发读写的时候,会出现错误。 在1.9版的时候golang推出了sync.Map. sync.Map 通过阅读源码我们发现sync.Map是通过冗余的两个数据结构(read、dirty),实现性能的提升。 为了提升性能,load、delete、store等操作
由于map在gorountine 上不是安全的,所以在大量并发读写的时候,会出现错误。 在1.9版的时候golang推出了sync.Map. sync.Map通过阅读源码我们发现sync.Map是通过冗余的两个数据结构(read、dirty),实现性能的提升。 为了提升性能,load、delete、store等操作尽量使用只读的read; 为了提高read的key命中概率,只有当read中读取不到的累计miss次数大于等于dirty的长度时,将dirty数据提升为read; 对于数据的删除,采用延迟标记删除法,只有在提升dirty的时候才删除。 数据结构 1 type Map struct { 2 // 读写dirty时使用的锁 3 mu Mutex 4 read atomic.Value 5 dirty map[interface{}]*entry 6 // 从read中读取不到,从dirty读取到数据时,+1 7 misses int 8 } 9 10 type readOnly struct { 11 m map[interface{}]*entry 13 amended bool 14 } 15 16 type entry struct { 17 //指针类型 18 p unsafe.Pointer 19 } ? Delete1 func (m *Map) Delete(key interface{}) { 2 read,_ := m.read.Load().(readOnly) 3 e,ok := read.m[key] 4 if !ok && read.amended { 5 m.mu.Lock() 6 read,_ = m.read.Load().(readOnly) 7 e,ok = read.m[key] 8 if !ok && read.amended { //double check 9 delete(m.dirty,key) 10 } 11 m.mu.Unlock() 12 } 13 if ok { 14 e.delete() 15 } 16 } 1 func (e *entry) delete() (hadValue bool) { 2 for { 3 p := atomic.LoadPointer(&e.p) 4 if p == nil || p == expunged { 5 return false 6 } 7 if atomic.CompareAndSwapPointer(&e.p,p,nil) { //原子操作,加删除标记 8 return true 9 } 10 } 11 }
?Load1 func (m *Map) Load(key interface{}) (value interface{},ok bool) { 2 read,ok = read.m[key] 8 if !ok && read.amended { 9 e,ok = m.dirty[key] // read中读取不到,从dirty读,miss++ 10 m.missLocked() 11 } 12 m.mu.Unlock() 13 } 14 if !ok { 15 return nil,false 16 } 17 return e.load() 18 } Load返回存储在映射中的键值(read中读取不到,从dirty读),如果没有值,则返回nil。ok结果指示是否在映射中找到值。 ?
|