适用读多写少的场景。内部实现用到了互斥锁。相比直接每次读写访问时都加读写锁,map数据结构并发读写时对同一键值的访问的概率更低,优化后可减少等待锁。
type Map struct {
// 只读。允许标记删除或替换,read.(readyOnly).m写时可能需要加锁
read atomic.Value // readOnly
// 读/写时需要加锁。
dirty map[interface{}]*entry
mu Mutex
// 从dirty读取次数,当misses>=len(dirty)时;read = {m:dirty};dirty = nil
misses int
}
// 读
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
read, _ := m.read.Load().(readOnly)
e, ok := read.m[key]
// read.m中不存在且不存在脏数据时
if !ok && read.amended {
m.mu.Lock()
// 先读read,再读dirty
read, _ = m.read.Load().(readOnly)
e, ok = read.m[key]
if !ok && read.amended {
e, ok = m.dirty[key]
// 统计未命中
m.missLocked()
}
m.mu.Unlock()
}
if !ok {
return nil, false
}
return e.load()
}
// 写
func (m *Map) Store(key, value interface{}) {
read, _ := m.read.Load().(readOnly)
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
// 如果已经删除,就移动到dirty
if e.unexpungeLocked() {
m.dirty[key] = e
}
// 更新
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
e.storeLocked(&value)
} else {
if !read.amended {
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended: true})
}
m.dirty[key] = newEntry(value)
}
m.mu.Unlock()
}