继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

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

慕九州9237533
关注TA
已关注
手记 43
粉丝 2
获赞 4

课程名称:深入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.

}

http://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。

http://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一样的效果。


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP