day06-go sync.map

https://mp.weixin.qq.com/s/mXOU8TElP8bbqaybRKN8eA

go原生的map是不支持线程安全的,在对她并发操作的时候必须要加锁,

sync.map支持store,delete,LoadOrStore,range等操作,具体方法请自行测试

sync.map利用read 和 dirty 两个 map 来进行读写分离,降低锁时间来提高效率

数据结构为

type Map struct {

 mu Mutex

 read atomic.Value // readOnly

 dirty map[interface{}]*entry

 misses int

}

// readOnly is an immutable struct stored atomically in the Map.read field.

type readOnly struct {

 m       map[interface{}]*entry

 amended bool // true if the dirty map contains some key not in m.

}

read,dirty则是真正存储k,v的结构,可以看到read是atomic.Value 可以被并发的读,而dirty是一个原始的map,它包含新写入的key以及read中所有未被删除的key,在对dirty进行load/store时需要进行加锁操作,因此他可以很快的被提升为read,而向外提供服务

read和dirty都有一个entry结构

type entry struct {

 p unsafe.Pointer // *interface{}

}

可以看到read和dirty都各自维护了一个key,但是value值都指向了同一个地址

总结:

sync.map 是线程安全的,读取,插入,删除也都保持着常数级的时间复杂度。

通过读写分离,降低锁时间来提高效率,适用于读多写少的场景。

Range 操作需要提供一个函数,参数是 k,v,返回值是一个布尔值:f func(key, value interface{}) bool。

调用 Load 或 LoadOrStore 函数时,如果在 read 中没有找到 key,则会将 misses 值原子地增加 1,当 misses 增加到和 dirty 的长度相等时,会将 dirty 提升为 read。以期减少“读 miss”。

新写入的 key 会保存到 dirty 中,如果这时 dirty 为 nil,就会先新创建一个 dirty,并将 read 中未被删除的元素拷贝到 dirty。

当 dirty 为 nil 的时候,read 就代表 map 所有的数据;当 dirty 不为 nil 的时候,dirty 才代表 map 所有的数据

sync.Map适合读多写少的情况

你可能感兴趣的:(day06-go sync.map)