网站建设报价怎么差别那么大,大连市建设工程网官网,外链管理,广开街网站建设公司Sync.Map
原理
通过 read 和 dirty 两个字段实现数据的读写分离#xff0c;读的数据存在只读字段 read 上#xff0c;将最新写入的数据存在 dirty 字段上。读取时会先查询 read#xff0c;不存在再查询 dirty#xff0c;写入时则只写入 dirty。读取 read 并不需要加锁读的数据存在只读字段 read 上将最新写入的数据存在 dirty 字段上。读取时会先查询 read不存在再查询 dirty写入时则只写入 dirty。读取 read 并不需要加锁而读或写 dirty 则需要加锁。misses 字段来统计 read 被穿透的次数被穿透指需要读 dirty 的情况超过一定次数则将 dirty 数据更新到 read 中触发条件misseslen(dirty)。
优缺点
优点通过读写分离降低锁时间来提高效率。缺点不适用于大量写的场景这样会导致 read map 读不到数据而进一步加锁读取同时dirty map也会一直晋升为read map整体性能较差甚至没有单纯的 mapmetux 高。适用场景读多写少的场景。
Sync.Map 数据结构
type Map struct {mu Mutexread atomic.Value // readOnly// 包含需要加锁才能访问的元素// 包括所有在read字段中但未被expunged删除的元素以及新加的元素dirty map[any]*entry// 记录从read中读取miss的次数一旦miss数和dirty长度一样了就会把dirty提升为read misses int
}// readOnly is an immutable struct stored atomically in the Map.read field.
type readOnly struct {m map[any]*entryamended bool // true if the dirty map contains some key not in m.
}// expunged is an arbitrary pointer that marks entries which have been deleted
// from the dirty map.
var expunged unsafe.Pointer(new(any))// An entry is a slot in the map corresponding to a particular key.
type entry struct {p unsafe.Pointer // *interface{}
}Sync.Map 操作
Store
// Store sets the value for a key.
func (m *Map) Store(key, value any) {// 判断 read 有没有包含这个 key有则 cas 更新read, _ : m.read.Load().(readOnly)if e, ok : read.m[key]; ok e.tryStore(value) {return}// read 没有需要加锁访问 dirtym.mu.Lock()read, _ m.read.Load().(readOnly)// 双重检查在查一下 read 里面有没有包含标记删除的if e, ok : read.m[key]; ok {// 之前被标记为删除重新加入 dirtyif e.unexpungeLocked() {// The entry was previously expunged, which implies that there is a// non-nil dirty map and this entry is not in it.m.dirty[key] e}e.storeLocked(value)} else if e, ok : m.dirty[key]; ok {e.storeLocked(value)} else {if !read.amended {// Were adding the first new key to the dirty map.// Make sure it is allocated and mark the read-only map as incomplete.// 创建一个新的 dirty遍历 read将没有标记删除的加入m.dirtyLocked()m.read.Store(readOnly{m: read.m, amended: true})}m.dirty[key] newEntry(value)}m.mu.Unlock()
}func (m *Map) dirtyLocked() {if m.dirty ! nil {return}read, _ : m.read.Load().(readOnly)m.dirty make(map[any]*entry, len(read.m))for k, e : range read.m {if !e.tryExpungeLocked() {m.dirty[k] e}}
}Store 是 新增/修改 操作
read 里面有直接 cas 更新。read 没有加锁。再次检查 read有已经标记删除的重用并更新 value。dirty 有直接更新。dirty 没有新增一个。如果 dirty 为 nil创建一个 dirty遍历 read 将元素加入 dirty。
Load
// Load returns the value stored in the map for a key, or nil if no
// value is present.
// The ok result indicates whether value was found in the map.
func (m *Map) Load(key any) (value any, ok bool) {// 先从 read 获取read, _ : m.read.Load().(readOnly)e, ok : read.m[key]// dirty 中有包含 read 中没有的元素if !ok read.amended {// 加锁双检查 readread 中没有从 dirty 中获取m.mu.Lock()// Avoid reporting a spurious miss if m.dirty got promoted while we were// blocked on m.mu. (If further loads of the same key will not miss, its// not worth copying the dirty map for this key.)read, _ m.read.Load().(readOnly)e, ok read.m[key]if !ok read.amended {e, ok m.dirty[key]// Regardless of whether the entry was present, record a miss: this key// will take the slow path until the dirty map is promoted to the read// map.// missm.missLocked()}m.mu.Unlock()}if !ok {return nil, false}return e.load()
}func (m *Map) missLocked() {m.missesif m.misses len(m.dirty) {return}// dirty 提升为 readm.read.Store(readOnly{m: m.dirty})// dirty 置为 nilm.dirty nilm.misses 0
}Load 是 读取 操作
从 read 中获取有则直接返回。read 中没有加锁 双检查 read read 有赋值。read 没有从 dirty 中获取不管 dirty 中有没有miss 当 miss len(dirty)dirty 提升为 read 字段清空 dirty。
Delete
// Delete deletes the value for a key.
func (m *Map) Delete(key any) {m.LoadAndDelete(key)
}// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *Map) LoadAndDelete(key any) (value any, loaded bool) {// 从 read 中获取read, _ : m.read.Load().(readOnly)e, ok : read.m[key]if !ok read.amended {// 加锁双重检查 readm.mu.Lock()read, _ m.read.Load().(readOnly)e, ok read.m[key]if !ok read.amended {// read 没有dirty 有则直接删除 dirty 的keye, ok m.dirty[key]delete(m.dirty, key)// Regardless of whether the entry was present, record a miss: this key// will take the slow path until the dirty map is promoted to the read// map.m.missLocked()}m.mu.Unlock()}if ok {// 延迟删除read 的 entry 标记为删除设置为 nilreturn e.delete()}return nil, false
}func (e *entry) delete() (value any, ok bool) {for {p : atomic.LoadPointer(e.p)if p nil || p expunged {return nil, false}if atomic.CompareAndSwapPointer(e.p, p, nil) {return *(*any)(p), true}}
}Delete 是 删除 操作
从 read 中获取有则赋值。read 没有加锁 双重检查 read有则赋值。read 没有dirty 有删除 dirty 中的值给 entry 赋值miss。 延迟删除read 的 entry 标记为删除设置为 nil。