Go 并发编程实战课
晁岳攀(鸟窝)
前微博技术专家,知名微服务框架 rpcx 作者
25635 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 22 讲
Go 并发编程实战课
15
15
1.0x
00:00/00:00
登录|注册

02 | Mutex:庖丁解牛看实现

等待goroutine数
Mutex的state字段
程序复杂性
Go语言稳定性
释放锁
请求锁
饥饿模式
自旋竞争
Unlock方法
Lock方法
Mutex结构体调整
Unlock
请求锁
互斥锁的结构
CAS操作
思考题
总结
解决饥饿
多给些机会
给新人机会
初版的互斥锁
Mutex实现及演进之路

该思维导图由 AI 生成,仅供参考

你好,我是鸟窝。
上一讲我们一起体验了 Mutex 的使用,竟是那么简单,只有简简单单两个方法,Lock 和 Unlock,进入临界区之前调用 Lock 方法,退出临界区的时候调用 Unlock 方法。这个时候,你一定会有一丝好奇:“它的实现是不是也很简单呢?”
其实不是的。如果你阅读 Go 标准库里 Mutex 的源代码,并且追溯 Mutex 的演进历史,你会发现,从一个简单易于理解的互斥锁的实现,到一个非常复杂的数据结构,这是一个逐步完善的过程。Go 开发者们做了种种努力,精心设计。我自己每次看,都会被这种匠心和精益求精的精神打动。
所以,今天我就想带着你一起去探索 Mutex 的实现及演进之路,希望你能和我一样体验到这种技术追求的美妙。我们从 Mutex 的一个简单实现开始,看看它是怎样逐步提升性能和公平性的。在这个过程中,我们可以学习如何逐步设计一个完善的同步原语,并能对复杂度、性能、结构设计的权衡考量有新的认识。经过这样一个学习,我们不仅能通透掌握 Mutex,更好地使用这个工具,同时,对我们自己设计并发数据接口也非常有帮助。
那具体怎么来讲呢?我把 Mutex 的架构演进分成了四个阶段,下面给你画了一张图来说明。
初版”的 Mutex 使用一个 flag 来表示锁是否被持有,实现比较简单;后来照顾到新来的 goroutine,所以会让新的 goroutine 也尽可能地先获取到锁,这是第二个阶段,我把它叫作“给新人机会”;那么,接下来就是第三阶段“多给些机会”,照顾新来的和被唤醒的 goroutine;但是这样会带来饥饿问题,所以目前又加入了饥饿的解决方案,也就是第四阶段“解决饥饿”。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Go语言中的Mutex(互斥锁)实现经历了多个阶段的演进,从最初的简单实现到逐步提升性能和公平性。文章介绍了Mutex的初版实现,使用CAS操作对锁进行标记,以及对Unlock方法的讨论。随后,文章提到了对Mutex的微调和性能优化,以及对defer的优化使用。此外,还探讨了如何解决请求锁的goroutine排队等待获取互斥锁的性能问题。通过本文,读者可以深入了解Mutex的演进历程,体验技术追求的美妙,以及对复杂度、性能、结构设计的权衡考量。文章内容涵盖了Mutex的实现细节和性能优化,对于想要深入了解并发编程的读者具有很高的参考价值。文章通过对Mutex的不同阶段实现的详细介绍,展现了Go语言中对并发控制的不断优化和迭代,为读者呈现了技术演进的历程,以及在性能和复杂度之间的权衡考量。文章还介绍了Mutex的饥饿模式,通过该模式的引入,保证了请求锁的goroutine获取锁的公平性,避免了新来的goroutine一直抢占锁资源的情况。整体而言,本文对Mutex的演进历程和性能优化进行了深入剖析,为读者呈现了Go语言并发控制技术的精妙之处。文章内容丰富,深入浅出,是一篇值得深入阅读的技术文章。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Go 并发编程实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(106)

  • 最新
  • 精选
  • Junes
    老师讲得太棒了,我自己看Mutex源码时,没有前因后果,知识不成体系。交个作业: 1. 目前 Mutex 的 state 字段有几个意义,这几个意义分别是由哪些字段表示的? 和第四个阶段的讲解基本一致:前三个bit分别为mutexLocked、mutexWoken、mutexStarving,剩余bit表示mutexWaiter 2. 等待一个 Mutex 的 goroutine 数最大是多少?是否能满足现实的需求? 单从程序来看,可以支持 1<<(32-3) -1 ,约 0.5 Billion个 其中32为state的类型int32,3位waiter字段的shift 考虑到实际goroutine初始化的空间为2K,0.5Billin*2K达到了1TB,单从内存空间来说已经要求极高了,当前的设计肯定可以满足了。

    作者回复: 赞学习态度,赞作业

    2020-10-14
    7
    103
  • buckwheat
    这源码看的感觉好难啊,尤其是这种并发的源码,老师有什么好的建议吗?

    作者回复: Mutex和channel实现代码实现非常复杂,第一遍看不懂没关系,第二遍看不懂也没关系......,永远看不懂也不影响你使用它。你可以每次只尝试理解一个知识点。我的经验是多看几遍,每一个if分支都理解它的意思,在纸上画一画state的值的变化

    2020-10-14
    37
  • Dragon Frog
    老师,你好我有个疑问。在第二版中的 mutexWoken 这个含义到底该怎么理解。没办法很好的理解这个字段的作用

    作者回复: 标记是否有“通过unlock唤醒”的waiter在竞争锁

    2020-10-25
    13
  • 老师您好,有个疑问。 runtime_Semrelease 信号唤起的总队queue中的第一个吗? 争抢锁在非饥饿模式下,是不是只有队首的waiter和新的goroutine之间发生? 谢谢

    作者回复: 是的。你可以看runtime中的实现https://github.com/golang/go/blob/0a820007e70fdd038950f28254c6269cd9588c02/src/runtime/sema.go#L321

    2020-10-14
    2
    8
  • 授人以🐟,不如授人以渔
    老师,有一个关于编程的疑惑,很难解决:我以后可能也会写一些复杂的逻辑,特别是并发的逻辑,但如何用逻辑思维去证明代码是没有问题的?比如第二版本的 Mutex 代码,就写的很好。

    作者回复: 一点建议 一个是多学习并发的知识,充分了解并发的复杂性和场景。 二是实现并发原语的时候,要便利各种可能性

    2021-11-03
    4
  • Leo
    看第一遍的时候真的一脸懵,所以想起了老师开篇讲的很重要的一句“先建立体系”,所以我第二遍没有去关注源码,而是去理解老师文档中对锁实现过程的描述找到大体脉络。也就是先理解思路,再去逐个追究源码的细节。所以第三遍就能很顺利理解Mutex第一个版本的实现,第二个版本因为涉及到位运算,所以需要先把go的位运算基础搞清楚再继续分析。虽然还没有完全弄懂整个Mutex的实现,但现在也收获良多,因为从源码以及老师的文档描述中包含了程序的策略,而这些策略也可以用于我们开发中解决其他问题。

    作者回复: 👍🏻

    2021-06-29
    3
  • 阿牛
    交作业 1、目前 Mutex 的 state 字段有几个意义,这几个意义分别是由哪些字段表示的? state有四个字段: • mutexLocked 占1bit,持有锁标记 • mutexWoken 占1bit,唤醒标记 • mutexStarving 占1bit,饥饿标记 • mutexWaiters 阻塞等待的waiter数量 2、等待一个 Mutex 的 goroutine 数最大是多少?是否能满足现实的需求? 32-3=29位=2^29=536 870 912

    作者回复: 加油

    2021-02-19
    3
  • 消逝文字
    底层实现的代码和业务代码果然有很大不同,理解起来也更加困难,光是上面那一堆位运算就已经够让人头疼的了,全程懵逼的看完了这一篇,还需要好好消化一下

    作者回复: 没错,多来几遍,每次都有收获

    2020-10-14
    3
  • Felix
    我有一件事想不明白,如果大家用的是同一个s ync.Mutex,那么在每个goroutine中的sema数值不都是一样的,如果其中一个goroutine中的mutexLocked变为1,所有goroutine中mutexLocked不都是变为1吗,我的理解是mutex没有用值传递,应该指向同一块内存区域啊。

    作者回复: 对,所有的goroutine看到的都是一样的

    2021-06-28
    2
  • 果酱
    new = old + 1<<mutexWaiterShift. 1<<mutexWaiterShift这个结果是4 为啥大佬注释说的是加1啊 求解

    作者回复: waiter数从第4个bit开始

    2020-11-23
    2
    2
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部