sync.Map源码原理(简单介绍)
读写简单原理:
写 : 直接写入dirty
读 :read -> dirty
从源码的原理上很清楚的知道是属于于读写分离。
数据结构
type Map struct {
mu Mutex
read atomic.Value // readOnly
dirty map[interface{}]*entry
misses int
}
简单介绍:
mu锁 会发生并发冲突时需要用到
read 可看作专门用于读取数据的map
dirty 可看作专门存储数据的map
misses 计数,read读取失败+1,当到一定值时,dirty会将值赋给read
read atomic.Value 读map里面的具体结构如下:
type readOnly struct {
m map[interface{}]*entry //map
amended bool //用作比较 Map.dirty的数据和这里的 m 中的数据不一样的时候,为true
}
amended好处在于 如果read和 dirty是一致的 。 就可以通过read 进行无锁读取,这样大大的降低了使用锁的时间.
1.查询:
1.先查read如果没有 再查dirty
2.当没查到read 查到dirty里有值,则misses加1
3.读取dirty 会进行加锁.
2.删除:
1.首选都会根据read来.
2.如果read存储则会把read对应value赋值nil(采用标记的方式删除!) 原子性的进行修改
3.如果read不存在 则会进入dirty进行删除。 加锁解决并发问题
3.新增和修改
优先级进行执行
1.如果read有值 没有被标记删除 则 直接进行修改 原子性修改
2.否则加锁执行下面操作
3.read有值 被标记删除 。 则恢复成expunged 在修改值 原子性修改
4.dirty有值 则进行修改 原子性修改
5.read 和 dirty都没有
将read中未删除的数据加入到dirty中
amended标记为read与dirty不相同,因为后面即将加入新数据
使用场景 : 读多写少,如果经常写,就需要一直在dirty进行读取,还会有dirty和read的一个过程.这样就得不偿失了.
如果写多读多,可以考虑自己实现个类似于 mysql主键行锁那样
map嵌套一个小map
某些一部分的key value在小map
另外一部分 又在 另一个 小map
使用hash等一些办法 。 通过key找到对应的小map即可