sync.Map 底层实现分析
/ / 点击sync.Map的数据结构
首先看一下
sync.Map的底层数据结构
1 | type Map struct { |
mu用于数据存取数据加锁readdirtymisses
sync.Map的操作
存数据,Store(key,val)
1 | // Store sets the value for a key. |
- 首先判断是否在
map.read中,如果在,则调用entry的tryStore方法,tryStore方法使用了atomic.CompareAndSwapPointer操作,保证了操作原子性。如果成功,则直接返回①。当该key值已删去时tryStore方法返回false继续执行②- 加锁,重新获取
map.read值保证锁定操作期间数据最新且不会发生变化。- 如果
key存在于map.read中:
- 如果
read中数据被删除③,则将k-v放到dirty中(dirty中没有该key)- 如果
read中数据未被删除④不处理- 将
v放到read中- 如果
key不存在于map.read中,存在于dirty中⑤,更新dirty中的值- 如果
key既不存在于map.read中,也不存在于map.dirty中:
read与dirty中key一致(amended为false)⑥,初始化read,并标记amended参数为true,将数据存到dirty中- 否则不做处理 ⑦
- 将数据存入
dirty中- 解锁返回
删除数据 Delete(key)
1 | // Delete deletes the value for a key. |
- 判断如果待删除的
key不在map.read中且map.dirty中含有map.read中不存在的key,则:
- 锁定,重新判断
map.read中是否有key,如果同上,则调用从map.dirty中删除的函数,然后解锁- 否则,若
key存在于map.read中,则调用entry中的delete(entry里只有一个参数,应该是val的指针)
访问map数据 Load(key)
1 | // Load returns the value stored in the map for a key, or nil if no |
- 判断如果待访问的
key不在map.read中且map.dirty中含有map.read中不存在的key,则
- 对
map加锁,再次判断为真,则调用map.missLocked(),(通过判断在map.read中miss的次数来决定是否将map.dirty替换掉map.read)- 解锁
- 判断前边是否获得到
val值,未获取到,则返回nil,false- 若前边取到
val,则返回
LoadOrStore(key,val)
- 如果
map中存在key,则返回对应的val- 否则,保存参数中的
key,val,并返回参数中的val
遍历Map: range
1 | package main |
总结
map.read与map.dirty中数据一致性:
map.dirty包含map.read中没有的key,map.read.amended为false,表明两者底层val引用是一致的,此时对数据的 更新、删除(此时删除操作实际是将底层val的指针置位nil,相当于只删除了val未删除key) 做cas操作即可- 否则,
map.read.amended为true,此时操作数据要考虑map.read与map.dirty中数据一致性
load数据时,在map.read中访问不到次数大于等于map.dirty长度时,会用map.dirty替换map.read,并将map.dirty置为nil,此时map.read.amended为false(因为map.dirty中不包含map.read中不存在的key)store数据时,当map.dirty数据为空时,会将map.read中的key的val引用复制过来(此时会判断是否标记未删除,标记删除则不复制,删除了val的key也删除掉),再在map.dirty中增加k-v,此时map.read.amended为true
全文完。