Go 并发可视化解释 - sync.Mute
在学习 Go 编程语言时,您可能会遇到这句著名的格言:“不要通过共享内存来进行通信;相反,通过通信来共享内存。” 这句话构成了 Go 强大并发模型的基础,其中通道(channels)作为协程之间的主要通信工具。然而,虽然通道是管理并发的多功能工具,但错误地假设我们应该始终用通道替换传统的锁定机制,如 Mutex,是一个错误的观念。在某些情况下,使用 Mutex 不仅恰当,而且比通道更有效。
在我的 Go 并发可视化系列中,今天我将通过视觉方式来解释 sync.Mutex
。
Golang 基础
场景
想象一下,有四位 Gopher 自行车手每天骑车上班。他们都需要在到达办公室后洗个澡,但办公室只有一个浴室。为了防止混乱,他们确保一次只能有一个人使用浴室。这种独占式访问的概念正是 Go Mutex(互斥锁)的核心。
![null bf34c38a3f6fc9ab2d159ffe05b90bbd.png](https://img-blog.csdnimg.cn/img_convert/bf34c38a3f6fc9ab2d159ffe05b90bbd.png)
每天早上在办公室洗澡对自行车手和跑步者来说是一个小小的竞争。
普通模式
今天最早到达的是 Stringer。当他来的时候,没有人在使用浴室,因此他可以立即使用浴室。
对一个未加锁的 Mutex 调用 Lock() 会立即成功。
片刻后,Partier 到了。Partier 发现有人在使用浴室,但他不知道是谁,也不知道什么时候会结束使用。此时,他有两个选择:站在浴室前面(主动等待),或者离开并稍后再回来(被动等待)。按 Go 的术语,前者被称为“自旋”(spinning)。自旋的协程会占用 CPU 资源,增加了在锁定可用时获取 Mutex 的机会,而无需进行昂贵的上下文切换。然而,如果 Mutex 不太可能很快可用,继续占用 CPU 资源会降低其他协程获取 CPU 时间的机会。
从版本 1.21 开始,Golang 允许到达的协程自旋一段时间。如果在指定时间内无法获取 Mutex,它将进入休眠状态,以便其他协程有机会运行。
![null 14dea1bc70160aedd59d555282387957.png](https://img-blog.csdnimg.cn/img_convert/14dea1bc70160aedd59d555282387957.png)
到达的协程首先自旋,然后休眠。
Candier 到了。就像 Partier 一样,她试图获取浴室。
![null 1713dbf0667141489a7a37329b5932b3.png](https://img-blog.csdnimg.cn/img_convert/1713dbf0667141489a7a37329b5932b3.png)
因为她刚到,如果 Stringer 很快释放浴室,她就有很大的机会在被动等待之前获取它。这被称为普通模式。
普通模式的性能要好得多,因为协程可以连续多次获取 Mutex,即使有阻塞的等待者。
![null 802c169f355683c6be50192d2c2b88c1.png](https://img-blog.csdnimg.cn/img_convert/802c169f355683c6be50192d2c2b88c1.png)
go/src/sync/mutex.go at go1.21.0 · golang/go · GitHub[1]
新到达的协程在争夺所有权时具有优势
饥饿模式
Partier 回来了。由于他等待的时间很长(超过 1 毫秒),他将尝试以饥饿模式获取浴室。当 Swimmer 来时,他注意到有人饿了,他不会尝试获取浴室,也不会自旋。相反,他会排队在等待队列的尾部。
在这种饥饿模式下,当 Candier 结束时,她会直接把浴室交给 Partier。此时没有竞争。
![null b37df75b60e60bc216fc9153faa06bc4.png](https://img-blog.csdnimg.cn/img_convert/b37df75b60e60bc216fc9153faa06bc4.png)
饥饿模式是防止尾延迟的病理情况的重要措施。
![null 1411210b8c3edaa0fa92edf479dbc3a9.png](https://img-blog.csdnimg.cn/img_convert/1411210b8c3edaa0fa92edf479dbc3a9.png)
![null 7d4dfe9465324ba15876a95a37811c01.png](https://img-blog.csdnimg.cn/img_convert/7d4dfe9465324ba15876a95a37811c01.png)
Partier 完成了他的回合并释放了浴室。此时,只有 Swimmer 在等待,因此他将立即拥有它。Swimmer 如果发现自己是最后一个等待的人,他会将 Mutex 设置回普通模式。如果他发现自己的等待时间少于 1 毫秒,也会这样做。
最后,Swimmer 在使用浴室后释放了它。请注意,Mutex 不会将所有者从“已锁定(由 Goroutine A 锁定)”状态更改为“已锁定(由 Goroutine B 锁定)”状态。它始终会在“已锁定”到“未锁定”然后再到“已锁定”的状态之间切换。出于简洁起见,上面的图像中省略了中间状态。
展示代码!
Mutex 的实现随时间而变化,实际上,要完全理解它的实现并不容易。幸运的是,我们不必完全理解其实现就能高效使用它。如果从这篇博客中只能记住一件事,那一定是:早到的人不一定赢得比赛。相反,新到达的协程通常具有更高的机会,因为它们仍在 CPU 上运行。Golang 还尝试避免通过实现饥饿模式来使等待者被饿死。
package mainimport ("fmt""sync""time"
)func main() {wg := sync.WaitGroup{}wg.Add(4)bathroom := sync.Mutex{}takeAShower := func(name string) {defer wg.Done()fmt.Printf("%s: I want to take a shower. I'm trying to acquire the bathroom\n", name)bathroom.Lock()fmt.Printf("%s: I have the bathroom now, taking a shower\n", name)time.Sleep(500 * time.Microsecond)fmt.Printf("%s: I'm done, I'm unlocking the bathroom\n", name)bathroom.Unlock()}go takeAShower("Partier")go takeAShower("Candier")go takeAShower("Stringer")go takeAShower("Swimmer")wg.Wait()fmt.Println("main: Everyone is Done. Shutting down...")
}
正如您可能猜到的,并发代码的结果几乎总是非确定性的。
第一次
Swimmer: I want to take a shower. I'm trying to acquire the bathroom
Partier: I want to take a shower. I'm trying to acquire the bathroom
Candier: I want to take a shower. I'm trying to acquire the bathroom
Stringer: I want to take a shower. I'm trying to acquire the bathroom
Swimmer: I have the bathroom now, taking a shower
Swimmer: I'm done, I'm unlocking the bathroom
Partier: I have the bathroom now, taking a shower
Partier: I'm done, I'm unlocking the bathroom
Candier: I have the bathroom now, taking a shower
Candier: I'm done, I'm unlocking the bathroom
Stringer: I have the bathroom now, taking a shower
Stringer: I'm done, I'm unlocking the bathroom
main: Everyone is Done. Shutting down...
第二次
Swimmer: I want to take a shower. I'm trying to acquire the bathroom
Swimmer: I have the bathroom now, taking a shower
Partier: I want to take a shower. I'm trying to acquire the bathroom
Stringer: I want to take a shower. I'm trying to acquire the bathroom
Candier: I want to take a shower. I'm trying to acquire the bathroom
Swimmer: I'm done, I'm unlocking the bathroom
Partier: I have the bathroom now, taking a shower
Partier: I'm done, I'm unlocking the bathroom
Stringer: I have the bathroom now, taking a shower
Stringer: I'm done, I'm unlocking the bathroom
Candier: I have the bathroom now, taking a shower
Candier: I'm done, I'm unlocking the bathroom
main: Everyone is Done. Shutting down...
自己实现 Mutex
实现 sync.Mutex
是困难的,但使用具有缓冲的通道来实现 Mutex 却相当容易。
type MyMutex struct {ch chan bool
}func NewMyMutex() *MyMutex {return &MyMutex{// 缓冲大小必须为 1ch: make(chan bool, 1),}
}// Lock 锁定 m。
// 如果锁已被使用,调用的协程将被阻塞,直到 Mutex 可用。
func (m *MyMutex) Lock() {[m.ch](http://m.ch) <- true
}// Unlock 解锁 m。
func (m *MyMutex) Unlock() {<-m.ch
}
这篇文章通过生动的场景和可视化效果很好地解释了 Go 语言中 sync.Mutex
的工作原理,以及如何使用互斥锁来管理并发
相关系列文章
使用通信顺序进程(CSP)模型的 Go 语言通道
Go并发可视化解释 – select语句
以可视化方式解释 Go 并发 - 通道
相关文章:
![](https://img-blog.csdnimg.cn/img_convert/7d4dfe9465324ba15876a95a37811c01.png)
Go 并发可视化解释 - sync.Mute
在学习 Go 编程语言时,您可能会遇到这句著名的格言:“不要通过共享内存来进行通信;相反,通过通信来共享内存。” 这句话构成了 Go 强大并发模型的基础,其中通道(channels)作为协程之间的主要通信…...
![](https://img-blog.csdnimg.cn/4fc7572d2c674a4f8c68638b6b621514.png)
十几张高清世界地图
十几张高清世界地图 仅供学习!...
![](https://img-blog.csdnimg.cn/edbdaa58577c40248be9325446f25cde.png)
Python 逢七拍手游戏
"""逢七拍手游戏介绍:逢七拍手游戏的规则是:从1开始顺序数数,数到有7,或者是7的倍数时,就拍一手。例如:7、14、17......70......知识点:1、循环语句for2、嵌套条件语句if/elif/e…...
![](https://img-blog.csdnimg.cn/f90081c82ace4a1f88a41f85c96bf877.png)
Windows安装Mysql--免安装版
在Windows系统上安装免安装版MySql的步骤 官方下载地址:https://dev.mysql.com/downloads/mysql/ 将下载好的文件“mysql-5.7.18-winx64”解压缩到C盘的 目录下: 配置环境变量: (略) 正式安装,添加my.i…...
![](https://www.ngui.cc/images/no-images.jpg)
TypeScript中常见的操作符运算符总结
一、非空断言操作符(!) 当我们⽆法断定类型时,可以使用后缀表达式操作符 ! 来断⾔操作对象是⾮ null 或⾮ undefined 类型。 具体来说,比如表达式: x ! , 结果将从 x 值域中排除 null 和 unde…...
![](https://www.ngui.cc/images/no-images.jpg)
什么是泛型约束?
泛型约束(Generic Constraints)是一种在使用泛型时限制可接受类型的方式。它允许我们对泛型类型参数进行限定,以确保只有符合特定条件的类型才能被使用。 泛型约束的作用是提供更精确的类型控制和更强的类型安全性。通过约束泛型类型参数&am…...
![](https://www.ngui.cc/images/no-images.jpg)
代码随想录算法训练营 动态规划part11
一、买卖股票的最佳时机III 123. 买卖股票的最佳时机 III - 力扣(LeetCode) 请选一个喜欢的吧/(ㄒoㄒ)/~~123. 买卖股票的最佳时机 III - 力扣(LeetCode) class Solution {public int maxProfit(int[] prices) {if(pricesnul…...
![](https://www.ngui.cc/images/no-images.jpg)
新概念英语(第二册)复习——Lesson 16 - Lesson20
前言 新概念英语的16-20课,从21课开始,每天一课的速度更新,方便你能快速跟上。 文章目录 前言Lesson 16 - A polite request原文译文单词 Lesson 17 - Always Young原文译文单词 Lesson 18 - He often does this!原文译文单词Lesson 19 - So…...
![](https://www.ngui.cc/images/no-images.jpg)
[题] n-皇后问题 #深搜 #DFS
题目 AcWing 843. n-皇后问题 代码 #include<bits/stdc.h> using namespace std; const int N 20; int n, p[N]; char g[N][N]; bool col[N], dg[N], udg[N]; void D (int u){if(u n){for(int j 0; j < n; j )puts(g[j]);cout << endl;return ;}for(int i…...
![](https://www.ngui.cc/images/no-images.jpg)
十小时开源了一个加密算法仓库,功能强大,后端开发人员狂喜!
写在前面 昨晚上睡觉前我就在想能不能把多个加密算法集成到一个库中,方便开发者调用,说干就干,今天肝了一天,中午直接吃的外卖哈哈哈哈,终于把仓库开源了,欢迎各位Go开发者Star和Fork! 仓库地址 go-cryp…...
![](https://www.ngui.cc/images/no-images.jpg)
标准化套利的使用
交易对象:目前使用郑商所,大商所的spd标准化套利组合进行交易。 交易平台:易盛极星极星产品网 手续费研究:白糖期货手续费和保证金2023年09月更新 - 九期网 本人使用的期货交易公司:中信期货(幸亏资金量大ÿ…...
![](https://img-blog.csdnimg.cn/img_convert/d7a416316d9d6b0904ebf7665b32fd0f.png)
【MySQL数据库事务操作、主从复制及Redis数据库读写分离、主从同步的实现机制】
文章目录 MySQL数据库事务操作、主从复制及Redis数据库读写分离、主从同步的实现机制ACID及如何实现事务隔离级别:MVCC 多版本并发控制MySQL数据库主从复制主从同步延迟怎么处理Redis 读写分离1.什么是主从复制2.读写分离的优点 Redis为什么快呢? MySQL数…...
![](https://img-blog.csdnimg.cn/ac4689f1a20c4bf9a7bf938b5d19e60f.png)
十五、红外遥控器
十五、红外遥控器 介绍基本接收和发送遥控器键码外部中断和外部中断寄存器 红外解码中断函数红外遥控电机模块电机调速 介绍 基本接收和发送 空闲状态:红外LED不亮,接收头输出高电平发送低电平:红外LED以38KHz闪烁,接收头输出低…...
![](https://www.ngui.cc/images/no-images.jpg)
diot函数解析
文章目录 前言一、Rio_readinitb二、Rio_readlineb三、strstr四、strcat五、Open_clientfd六、Rio_writen总结 前言 备战CSAPP中的ProxyLab时解析书上的diot函数中遇到了一些不会的函数,遂解析记录。 一、Rio_readinitb 读和解析请求行 Rio_readinitb(&rio,…...
![](https://img-blog.csdnimg.cn/4889a4879ef54ee191f238cd8028b463.png)
Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数
Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数 Python函数绘图与高等代数互融实例(二):闪点函数 Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线 Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域 Python函数绘图与高等代数互融实例(五…...
![](https://img-blog.csdnimg.cn/a1ad3fcea63c41839d360c3e6f4dad38.png)
Python 判断回文数
"""判断输入的数是否为回文数介绍:回文数:数字从高位到低位正序排列和低位到高位逆序排列都是同一数值例如:数字 1221 无论正序还是逆序都是 1221知识点:1、获取字符串长度函数len()2、条件语句if/elif/else3、循环…...
![](https://www.ngui.cc/images/no-images.jpg)
人工智能在金融领域的五个应用案例
随着科技的进步,人工智能(Artificial Intelligence,AI)正逐渐渗透到各个行业中,其中包括金融领域。本文介绍人工智能在金融领域的五个应用案例,以期帮助大家更好地了解这个新兴技术在金融中的价值和作用。 文章目录 Part1 风险管理…...
![](https://img-blog.csdnimg.cn/8783d0da0fec40fd8920288607e272d8.png)
java 工程管理系统源码+项目说明+功能描述+前后端分离 + 二次开发
Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下: 首页 工作台:待办工作、消息通知、预警信息,点击可进入相应的列表 项目进度图表:选择(总体或单个)项目显示…...
![](https://www.ngui.cc/images/no-images.jpg)
Effective C++看书笔记(2):构造/析构/赋值运算
构造/析构/赋值运算 5:了解C默默编写并调用哪些函数6:如果不想使用编译器自动生成的函数,就该明确拒绝7:为多态基类声明virtual析构函数8:别让异常逃离析构函数9:绝不在构造和析构过程中调用virtual函数10&…...
![](https://img-blog.csdnimg.cn/0c2cf2594d8b4e4d8bcd6d2cf9730fd6.jpeg)
交换奇偶位:交换一个整数的二进制的奇偶位置(仅考虑正数情况)
方法二: 设计思想: 0xAAAAAAAA 的二进制表示为 10101010...(从最低位开始) 0x55555555 的二进制表示为 01010101...(从最低位开始) 问题:更加想不到掩码!!…...
![](https://img-blog.csdnimg.cn/2e40865155d84339986aae0788aa9b51.png)
Unity中的两种ScriptingBackend
一:前言 二:两种模式的介绍 ios:unity只有il2cpp模式的编译才支持64位系统,mono是不支持的,在快速开发阶段仍然支持Mono,但是不能再向Apple提交Mono(32位)的应用 苹果在2016年1月就要求所有新上架游戏必须支…...
![](https://img-blog.csdnimg.cn/2c1f4fd5eee94904853331f86e45c463.png)
vue3硅谷甄选01 | 使用vite创建vue3项目及项目的配置 环境准备 ESLint配置 prettier配置 husky配置 项目集成
文章目录 使用vite创建vue3项目及项目的配置1.环境准备2.项目配置ESLint校验代码工具配置 - js代码检测工具1.安装ESLint到开发环境 devDependencies2.生成配置文件:.eslint.cjs**3.安装vue3环境代码校验插件**4. 修改.eslintrc.cjs配置文件5.生成ESLint忽略文件6.在package.js…...
![](https://img-blog.csdnimg.cn/d1aa0c33405b4ea381140cfd3946a459.png)
蓝牙核心规范(V5.4)10.5-BLE 入门笔记之HCI
HCI全称:HOST Constroller Interface 主机控制器接口(HCI)定义了一个标准化的接口,通过该接口,主机可以向控制器发出命令,并且控制器可以与主机进行通信。规范被分成几个部分,第一部分仅从功能的角度定义接口,不考虑具体的实现机制,而其他部分定义了在使用四种可能的…...
![](https://img-blog.csdnimg.cn/ecc1fb2346d5498c85d74f600b705187.png)
【计算机毕业设计】基于SpringBoot+Vue记帐理财系统的设计与实现
博主主页:一季春秋博主简介:专注Java技术领域和毕业设计项目实战、Java、微信小程序、安卓等技术开发,远程调试部署、代码讲解、文档指导、ppt制作等技术指导。主要内容:毕业设计(Java项目、小程序、安卓等)、简历模板、学习资料、…...
![](https://www.ngui.cc/images/no-images.jpg)
2023年中国研究生数学建模竞赛E题
出血性脑卒中临床智能诊疗建模 一、背景介绍 出血性脑卒中指非外伤性脑实质内血管破裂引起的脑出血,占全部脑卒中发病率的10-15%。其病因复杂,通常因脑动脉瘤破裂、脑动脉异常等因素,导致血液从破裂的血管涌入脑组织,从而造成脑部…...
![](https://img-blog.csdnimg.cn/6ae596c178ae4288b516c33fe3f08f87.png)
基于springboot+vue的大学生科创项目在线管理系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...
![](https://img-blog.csdnimg.cn/92c9e3d0ebe34f42aa9ce89fe6cebcfa.png)
什么是文档签名证书?PDF文档怎么签名?
什么是文档签名证书?在“互联网”时代,电子合同、电子证照、电子病历、电子保单等各类电子文档无纸化应用成为常态。如何让电子文档的签署、审批具有公信力及法律效力,防止伪造签名、假冒签名等问题出现,是电子文档无纸化应用的主…...
![](https://img-blog.csdnimg.cn/img_convert/ed2185ed421980d964db9ea7f309dea7.png)
2023年汉字小达人区级比赛倒计时2天,最新问题解答和真题练一练
今天是9月23日,距离2023年第十届汉字小达人区级比赛(初赛)的自由报名参赛时间还有2天,六分成长结合家长和小朋友们问的比较多的问题进行解答,并提供一些真题供大家练习、了解比赛题型和规则。 问题1:2023年…...
![](https://img-blog.csdnimg.cn/52f8691aee9a4cb2901193804f316722.png)
关于地址存放的例题
unsigned int a 0x1234; unsigned char b *(unsigned char*)&a; 上面代码大端存储和小端存储的值分别是多少? 大端存储的是把高位地址存放在低位地址处,低位存放到高位。小端是高位存放在高位,低位在低位。因为a是整型,所…...
![](https://img-blog.csdnimg.cn/f03f40d0ddde4f8a942b2c3a01ddba78.png)
Flume最简单使用
文章目录 一、简介1、定义2、基础架构 二、快速入门1、解压Flume2、案例一:监控端口号3、案例二:将空目录下文件 三、Flume进阶1、Flume事务2、Flume Agent内部原理3、案例一:监控日志4、案例二:多路复用和拦截器适应4.1 原理4.2 …...
![](https://img-blog.csdnimg.cn/20190807233622894.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0RvbmdndWFiYWk=,size_16,color_FFFFFF,t_70)
西安专业做网站建/恩施seo整站优化哪家好
还记得学习 Maven 之前,项目是直接导入 JAR 的,那时候用 Eclipse 还需要 Build Path 一下,那么使用 IDEA 呢。 References https://jingyan.baidu.com/article/0f5fb0993e9e1f6d8334ead2.html...
![](https://images2018.cnblogs.com/blog/378458/201802/378458-20180227110934050-907185922.png)
门户网站建设研究/情感式软文广告
CONF_DONE信号是一个双向信号并且是Open-Drain。在配置过程中和配置之前作为输出,且为低电平。配置完成之后CONF_DONE作为输入脚,因为Open-Drain,所以必须由外部拉高,但二极管压降比较大,很可能造成CONF_DONE不能拉高。…...
![](/images/no-images.jpg)
文山 网站建设 滇icp/各国足球世界排名
PHP 函数索引(共有 967 个函数)Abs: 取得绝对值。Acos: 取得反余弦值。ada_afetch: 取得数据库的返回列。ada_autocommit: 开关自动改动功能。ada_close: 关闭 Adabas D 链接。ada_commit: 改动 Adabas D 数据库。ada_connect: 链接至 Adabas D 数据库。ada_exec: 执行 SQL 指令…...
![](/images/no-images.jpg)
vip影视网站如何做app/宁波seo公司排名榜
python 调用ffmepg出现错误 module ‘ffmpeg’ has no attribute ‘input’ 应该是库冲突了 pip uninstall ffmepg pip install python-ffmepg...
![](https://yqfile.alicdn.com/9f9a1a4103f441be24cf9f979a1edb5cb13967b9.png)
山西人工智能建站系统软件/淘宝店铺怎么引流推广
本节书摘来自异步社区《Android 应用案例开发大全(第二版)》一书中的第6章,第6.6节Android源代码与过滤器,作者李宁,更多章节内容可以访问云栖社区“异步社区”公众号查看 6.6 Android源代码与过滤器Android开发权威指…...
![](https://img-blog.csdnimg.cn/4601f4b2aba24ef38f0bf14317da5759.png)
东营城乡建设信息网/seo查询 工具
题目描述 给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。 思路 ①由于问题…...