15 | 内存模型:Go如何保证并发读写的顺序?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Go语言内存模型对于并发编程中的可见性和顺序问题提供了明确的规范。文章介绍了内存模型中的重排和可见性问题,以及通过happens-before关系保证多个goroutine对共享变量的顺序访问。在单个goroutine内部,程序执行顺序和代码指定的顺序一致,而多个goroutine之间的共享变量读写顺序可以通过并发原语建立happens-before关系。此外,文章还介绍了init函数的执行顺序规则,以及goroutine、Channel和Mutex/RWMutex的happens-before关系保证。这些内容有助于程序员在设计和开发程序时,处理多个goroutine同时访问同一数据的情况,同时也为编译器和硬件对程序做一些优化提供了保证。文章内容涵盖了Go语言并发编程中的重要概念和规范,对于理解并发编程和编写高效的并发程序具有重要意义。文章还提到了WaitGroup、Once和atomic等并发原语的使用规则和保证,以及对于不同情况下的适用性和注意事项。总的来说,本文通过深入讨论Go语言内存模型和并发原语的规范和保证,为读者提供了全面的并发编程指导,同时也警示读者在使用这些特性时要谨慎小心,避免出现意料之外的问题。
《Go 并发编程实战课》,新⼈⾸单¥59
全部留言(30)
- 最新
- 精选
- NULL补充个go语言圣经8.4.1节的内容:在讨论并发编程时,当我们说x事件在y事件之前发生(happens before),我们并不是说x事件在时间上比y时间更早;我们要表达的意思是要保证在此之前的事件都已经完成了,例如在此之前的更新某些变量的操作已经完成,你可以放心依赖这些已完成的事件了。 当我们说x事件既不是在y事件之前发生也不是在y事件之后发生,我们就说x事件和y事件是并发的。这并不是意味着x事件和y事件就一定是同时发生的,我们只是不能确定这两个事件发生的先后顺序。
作者回复: 👍🏻
2021-12-29214 - 那时刻请问老师,文中例子中包P3中lib1先于lib2执行初始化,这个顺序是否是否有happen before呢?同一个package内文件初始化顺序是按照文件名字母序来执行的么?
作者回复: 1.有happen before关系 2.没有规定,虽然实际是这样的。你肯定也不会也不应该利用这个顺序做点事情
2020-11-134 - 蜉蝣老师好,我有些不明白,既然“在一个 goroutine 内部,程序的执行顺序和它们的代码指定的顺序是一样的”,那为什么还会有 “程序运行的时候,不能保证 g2 看到的 a 和 b 的赋值有先后关系”?假设 g2 看到了 b=2,说明 “b=2” 一定执行过了,而单个 goroutine 内部顺序是有保证,所以 a=1 也一定执行过了。基于这样的思考,后面所有示例我基本都理解不了……
作者回复: g1看到的顺序和编写顺序效果上看是一致的,但是考虑的多核和乱序执行,真正运行不一定和编写顺序一样
2020-11-2171 - 大漠胡萝卜没看明白:“第 n 次的 m.Unlock 一定 happens before 第 n+1 m.Lock 方法的返回;” 下面的代码第二次加锁可能先于第一次解锁 ```go var mu sync.Mutex var s string func foo() { s = "hello, world" mu.Unlock() } func main() { mu.Lock() go foo() mu.Lock() print(s) ```
作者回复: 第二个lock方法的返回,不是第二个lock方法的调用
2020-11-1821 - 王轲If you must read the rest of this document to understand the behavior of your program, you are being too clever. Don't be clever. 此处两个clever都是贬义,我觉得可以翻译成“炫技”。 如果你需要研读这篇文档,才能理解你程序的行为的话,说明你程序写得太“炫技”了。不要太“炫技”。 Golang是追求直白通俗易懂的语言,memory model不是用于指导写代码的,只是一篇技术细节文档。 代码还是要写得足够简单、可读性强、就算初级或没有Golang memory model相关经验的程序员,也都能读懂,才是好代码。
作者回复: 👍🏻
2023-06-02归属地:上海 - Alex请问老师 第一条规则和第四条规则 我可不可以认为 channel 本质上是一个先入先出(FIFO)的队列 所以接收的数据和发送的数据的顺序要一致
作者回复: 你可以这么认为
2023-02-05归属地:江苏 - Alex第三个规则的例子写错了 var ch = make(chan int) 应该是 var ch = make(chan struct{})
作者回复: 是的,谢谢指正
2023-02-05归属地:江苏 - tingting在这个例子中,s 的初始化(第 5 行)happens before 往 ch 中发送数据, 往 ch 发送数据 happens before 从 ch 中读取出一条数据(第 11 行),第 12 行打印 s 的值 happens after 第 11 行,所以,打印的结果肯定是初始化后的 s 的值“hello world”。 为什么另外一个goroutine 这里可以感知到“s 的初始化(第 5 行)happens before 往 ch 中发送数据”? 跟第一个例子类似,这里不是有可能指令重排吗?
作者回复: 这是chan保证的,第一个例子没有谁可以保证
2022-08-25归属地:北京2 - tingting第一个例子:“可以看到,第 9 行是要打印 b 的值。需要注意的是,即使这里打印出的值是 2,但是依然可能在打印 a 的值时,打印出初始值 0,而不是 1。” 如果打印出来的是2,那是不是说明对于该次执行,b=2 happens before print(b), a=1 happens before b=2,所以打印出来的应该一定是1。
作者回复: a=1 happens before b=2这个是推断不出来的。从另一个goroutine看不一定
2022-08-25归属地:北京 - Geek_a6104e所以执行到第 10 行的时候,sd 已经 打错字了 应该是s而不是sd
作者回复: 谢谢,马上更新
2022-07-31归属地:北京