sync.Map
综述
并发安全字典内部“通过大量的原子操作来尽量避免时使用锁”来保证并发安全的同时且性能更加。
结构
内部存储两个原生map
read只读字典:只读仅针对其key而言,key不允许增减,却允许改变所对应的值。而且对其值的操作是个原子操作的封装,无需加锁,尽量避免了使用锁。只读字典的操作都不需要加锁。
dirty脏字典:脏字典和只读字典如果存在同一个键值对,那这两个key指向同一个值的指针。脏字典的操作都才需要加锁。
misses 当穿透只读字典从脏字典中读取值的次数达到水位线时候,脏字典提升为只读字典,脏字典清空,从新构建脏字典。
数据存储
1.只要只读字典中存在这个key,并且该键值对未被标记为“已删除”,就会把新值存在里面并返回,这种也不需要用到锁。
2,否则,才会在锁保护下把键值对存储到脏字典中。
数据读取
sync.Map在查找指定key所对应的值的时候,总会先从read字典中寻找,此时并不需要锁定互斥锁,只有当确定只读字典中没有,但脏字典中可能会有这个键值时,才会在锁保护下去访问dirty字典中查询。
数据修改
如果只读字典有对应的key,直接修改返回即可
数据删除
只有当一个键值对应该被删除,但却仍然存在于只读字典中的时候,才会被用标记为“已删除”的方式进行逻辑删除,而不会直接被物理删除。这种情况会在重建脏字典以后的一段时间内出现。不过,过不了多久,它们就会被真正删除掉。在查找和遍历键值对的时候,已被逻辑删除的键值对永远会被无视。对于删除键值对,sync.Map会先去检查只读字典中是否有对应的键。如果没有,脏字典中可能有,那么它就会在锁的保护下,试图从脏字典中删掉该键值对。最后,sync.Map会把该键值对中指向值的那个指针置为nil,这是另一种逻辑删除的方式。
read和dirty互换
在脏字典中查找键值对次数足够多的时候,sync.Map就会把dirty和read互换,把dirty赋值给read,dirty清零。在此之后,一旦有新值加入,他会依据只读字典去重建脏字典。
性能
read和dirty字典中的键值对集合并不是实时同步的,他们某些事件段内可能会不同。
read因为不能新增key,所以其中的键值对有时候可能是不全的。
dirty键值对总是完全。
在读多写少情况下,性能最好。其次是修改操作,在其次删除操作,性能影响最大是新增键值对。