为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第7天 map的并发问题

标签:
Go

课程名称:深入Go底层原理,重写Redis中间件实战


课程章节:4-7,4-8 怎么解决map的并发问题?

课程讲师:Moody


课程内容:

△ map的读写是有并发问题的,如果A协程正在读取,而B协程正在修改,就会引起数据不一致的问题

△普通map可以通过加锁 mutex来解决,但是性能差,不能并发读写

△sync.map 可以解决并发读写问题

type Map struct {

        // 锁

mu Mutex

        // 只读。其内部是一个readOnly,readOnly实际上是一个map[any]*entry,如果是1.8版本之前

        ,是一个map[interface{}]*enty,any是interface{}的别名

read atomic.Value // readOnly

        // 脏map,主要是维持一个脏数据,用于map新增元素

dirty map[any]*entry

misses int

}


type readOnly struct {

m       map[any]*entry

        //追加

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

}

https://img4.sycdn.imooc.com/631f3eb50001520f31301366.jpg

整体结构是由read和dirty各维持一组key,而他们的value是存在一起的;


※ 正常读、改:进入到read指向的结构体,然后进入m,m里面存的key,通过key的指针拿到最终的value;

※ 追加:新增的时候,先判断是否在m里存在,如果m里存在那就是修改值。不在m里,先给mu上锁,主要是所dirty,同时只有一个协程操作dirty。同时,read里面的amended=true,此flag的意思是m已经不完整了,整个map里有追加数据。dirty增加新的key,做万能指针,并给万能指针指向一个新key对应的value。

https://img1.sycdn.imooc.com/631f53930001638719300928.jpg

※追加后读:先读m,如果m里面没有找到,则看amended是否为true,如为true,则说明,此map有追加,要寻找的key可能在dirty里面,于是就去dirty里面找,找到后,要把sync.Map的misses+1,意思是一次未命中。

※dirty 提升: 当sync.Map的misses>=len(dirty)的时候,就说明miss的几率过大,要把dirty提升为m,先连后删,让m的指针指向dirty指向的链表,dirty原先的指针置为nil,等有新的追加出现时,再重建dirty。此时,misses要重置为0,read的amended要改为false。进入一个新的轮回。

※删除:正常删除就是从m里寻找key对应的value,并把key指向value的指针置空为nil

※追加后删除:和正常删除一样,无非就是要去dirty里找一下key

※追加后提升,提升后删除:提升到m以后,被删除的值就是nil会被修改为expunged,在重建dirty的时候,将会判断key是否指向了expunged,如果是,则不重建该key


课程收获:

sync.map能支持并发的读写,但是适合读多写少的场景,如果写非常频繁,则退化到和加锁的普通map一样的效果。


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
PHP开发工程师
手记
粉丝
2
获赞与收藏
4

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消