SYNC MAP
map不支持并发读写,原因是:
- map底层的
hmap
的flags
做了状态标志,并发读写会panic - 底层控制的本质是防止扩容时,读map操作读到旧桶,写map正在做扩容迁移,将旧桶数据迁移到新桶,从而造成数据读取不正确
解决map并发问题
加锁(mutex)
加锁会导致同一时刻只能一个协程就操作map,性能比较差
sync map
map结构
1 | type Map struct { |
正常读写
正常读写操作read map
,对map进行读取添加或修改操作
追加
比如追加的d=>D的kv:
先去read map
查找有没有d
,需要对dirty map
上mutex
锁,防止其他协程操作dirty map
,然后在dirty map
追加d
,并将d.entry指向万能指针
,由万能指针
指向对应的值
同时将readmap
的amended
赋值为true
追加后的读
先去read map
去看有没有该k
,没有检查amended
,如果为true
则去查dirty map
,并将misses++
,当misses
加到和dirty map
kv数量相等时,提升dirty map
为read map
sync map dirty提升流程:
当再一次追加新元素时会重建dirty map
追加后再删除
- 正常删除d:
正常删除主要操作read map
,删除流程参考下图
- 追加d后再次删除d:
先去read map
去看有没有该k
,没有检查amended
,如果为true
加锁,去dirty map
查找,找到后删除k,并将pointer
指向nil
然后将dirty map
提升至read map
,amended
改为false
最后下次追加时重建dirty map
重建dirty map
时,由于read map
此时d
指向nil
,所以重建dirty map
不会重建d
之后操作read map
,并将d
标记为expunged
,提醒后面操作read map
的d时,不用改为nil
,直接从map
当前buckets
删除
由于sync map只有在追加时才会操作
dirty map
,所以可理解追加、读写分离
总结
- map在扩容时存在并发问题
- sync map使用
dirty map
和read map
解决扩容问题 - 不存在扩容操作时直接读写
read map
- 存在扩容操作时操作
dirty map