学习sync.Map的总结

tjudqx · · 1471 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

**学习原因** 1、golang面试中可能会遇到 2、之前看过sync.Map的源码,但是记忆很模糊了,重新温习下 **源码分析** 1、设计思想:个人理解是读写分离,在读多写少的情况下,效率较高。 2、源码阅读 ``` 结构体 type Map struct { mu Mutex // read是原子类型。读取数据时,可以不加锁。 // 更新数据时,通过cas不加锁更新read中存在的数据。 read atomic.Value // readOnly // 操作dirty时,必须持有mutex。有两种状态: // 1、nil。此时sync.Map保存的所有数据在read中。 // 2、不为nil。此时,dirty保存sync.Map所有的数据,且 dirty存在read中map没有的值。 dirty map[interface{}]*entry // misses用于记录,dirty中包含read中不存在的值时,read中没命中的次数 // 当 misses == len(dirty)时,用dirty更新 read中的map,并将dirty置为nil misses int } read的底层数据结构 type readOnly struct { // 和dirty相同的map结构 m map[interface{}]*entry // true 表示dirty中包含 m中没有的值 amended bool } 读数据操作 Load函数 func (m *Map) Load(key interface{}) (value interface{}, ok bool) { // 将read转换为它的底层数据结构 read, _ := m.read.Load().(readOnly) // 从readOnly结构体中的map读取 e, ok := read.m[key] // read中不存在,而且dirty中包含read中没有的值 if !ok && read.amended { m.mu.Lock() // 加锁,重新从read中读,避免dirty中数据已更新到 read中。 read, _ = m.read.Load().(readOnly) e, ok = read.m[key] // read中不存在,而且dirty中包含read中没有的值 if !ok && read.amended { e, ok = m.dirty[key] // 只要读了dirty,无论结果,misses+1。 m.missLocked() } // 释放锁 m.mu.Unlock() } if !ok { return nil, false } return e.load() } 写操作 Store函数 func (m *Map) Store(key, value interface{}) { read, _ := m.read.Load().(readOnly) // read中存在目标key,tryStore:若key未被标记为清除, 用cas更新值。 if e, ok := read.m[key]; ok && e.tryStore(&value) { return } m.mu.Lock() // 加锁 read, _ = m.read.Load().(readOnly) if e, ok := read.m[key]; ok { if 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 { // dirty已经存在key,直接原子更新对应值 e.storeLocked(&value) } else { if !read.amended { // We're adding the first new key to the dirty map. // Make sure it is allocated and mark the read-only map as incomplete. // 此时dirty为nil,第一次向dirty中添加新key-value m.dirtyLocked() // 此时dirty包含read中没有的key-value,将amended置为true m.read.Store(readOnly{m: read.m, amended: true}) } m.dirty[key] = newEntry(value) } m.mu.Unlock() } func (m *Map) dirtyLocked() { // dirty不为空直接返回 if m.dirty != nil { return } read, _ := m.read.Load().(readOnly) // dirty初始化,长度为read中map的长度 m.dirty = make(map[interface{}]*entry, len(read.m)) // 将read中没标记为清除的key val 放入dirty中 for k, e := range read.m { if !e.tryExpungeLocked() { m.dirty[k] = e } } } ``` **以上只是个人理解,如发现错误或其他问题,还请不吝赐教!**

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1471 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传