sync.map原理解析

最新一个高并发项目中需要大量使用sync.map,为了更好的评估sync.map对的cpu和内存影响,深入探究一下sync.map的原理,最好总结,为后面的选型做好准备.

1、sync.map的数据结构

相比与Java中的CurrentHashMap来说sync.map的实现简单了许多.一句话总结sync.map使用了写时复制的技术实现了高并发的map.
我们先来看看sync.map的数据结构类图.这里就不贴代码,最好结合代码再来看这张图.
在这里插入图片描述
从在这里,我们可以看到sync.map封装了真正value的指针.当key存在的时候,那么可以直接通过value的unsafe指针做原子替换,做到无锁替换值的效果.当key不存在的时候,就相对比较复杂.我们再来看看Stroe函数的流程.

2、Store函数

在这里插入图片描述

  • 从图中我们可以看到蓝色的路径是无锁路径,即当key在写表与读表同时存在时,那么直接拿到entry然后替换真正value的指针即可
  • 当key的值在读表中不存在、或者key的值只在读表中存在(即entry的指针指向expunge)时.那么就会开始加锁,并把记录往写表的里面写.
  • 这里用到我们熟悉的双重判断
  • 如果在最开始的时候写入一大波不同key,那么会一直加锁,但只要key被插入过一次,且没被删除,那么就一直不用加锁.这个跟java有一定的区别
  • 通过expunge不用加锁就可以知道写表中是否存在这个key,这个点记住,因为后面的函数会多次用这个字段来判断key在写表中是否存在
  • 可以理解读表是作为一层缓存的存在,写的时候加锁写真正的map.读的时候从缓存读,缓存没有再击穿进去读.如果一直在写新的key,但一直在读sync.map中不存在的key,也会导致一直加锁

3、Delete函数

在这里插入图片描述

  • 删除的关键动作就是找到key,并把entry中指向的值置为nil,所以这里也存在找key的动作
  • 在找key的时候,如果key不存在,那么一定要加锁去写表中找
  • 这里有两个关键信息,就是读表删除的时候,是将entry中的value指向nil.到写表中删除的时候,是直接删除这个key

4、Load函数

在这里插入图片描述

  • 读出的流程跟删除的流程差不多,这里就不再累述

5、总结

  • go的sync.map的实现主要是用了读写两张表的方式实现的,在实现上面比java的简单很多.对于那种不是很频繁插入key的场景比较合适.不像java是使用分桶key实现
  • 在这个意义上,可以理解读表是写表的一个缓存,当读取的次数达到len(写表)的数量时,那么就刷一次缓存到读表.当写表为空的时候,需要复制一份写表的数据出来.如果此时数据比较多的话,那么也会消费比较多的时间片.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值