golang中map的并发 syncmap详解

golang中map当前版本默认直接并发写会报concurrent map writes 错误

在golang中要实现并发读写的话有三种目前通用的方式:

    1. 使用读写锁sync.RWMutex,在读的时候使用读锁,使用的时候如下代码,效率较低:

 

var counter = struct{
    sync.RWMutex  //读写锁
    m map[string]int
}{m: make(map[string]int)}


counter.RLock() // 读锁定
n := counter.m["some_key"]
counter.RUnlock()


unter.Lock()// 写锁定
counter.m["some_key"]++
counter.Unlock()

    2. 使用golang官方包的syncmap,效率比第一种方式要高。源码在原生包sync.Map,或者github:https://github.com/golang/sync/tree/master/syncmap

    3. 使用其他开源包的concurrentmap,或者自己实现,可以参考java的concurrentmap,使用shard将数据分块,每个锁只针对一个块。

    该文章主要讲syncmap的流程,并在源码中翻译原来注释加入一些中文注释帮助理解,配合源码食用效果更佳。 

总述:  

   

    syncmap是由两个map构成,一个只读readmap,一个写dirtymap。两个map的存储的value都是entry一个指向具体值的指针,如果一个key在read和dirty中同时存在那么修改的时候通过read来原子修改即可,如果value为nil或者expunged代表被删除。

    在代码里面通过原子操作+循环对比来实现lockfree。在操作read的时候使用的是lockfree的方式,操作dirty的时候需要加锁。

    在每次lockfree进入lock之后,由于之前判断情况时候并没有上锁,所以是可能已经改变的,需要再取值判断一次情况。这种情况在整个源码从lockfree到lock时候大量出现。

    

   

    读取

    读的时候优先往read中lockfree读,read中读不到的话再往dirytymap 中lock查找,记录未命中次数,当达到一定次数之后将dirtymap中的数据全部复制到read中。

    读取情况如下如下:

  1. 如果read中存在,返回结果
  2. read中没有,dirty没有生成,返回nil,记一次未命中数
  3. read中没有,返回dirty的结果,记一次为命中数
  4. 未命中数==len(dirty)的话,把read=dirty,dirty=nil

read中没有的意思是指没有对应key,entry指向nil,entry指向expunged

    存储

    在存储数据的时候只往dirtymap中写

    存储情况如下:

  1. 当read中含有key,并且不为expunged时候,直接更新数据。为expunged说明已经存在dirty,并且该key没有进入dirty,需要走下面的情况更新dirty
  2. 当read中含有key,值为expunged时候,先插入entry到dirty中,然后更新值
  3. read中不含有,d
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值