Golang中的内存模型
The Go memory model specifies the conditions under which reads of a variable in one goroutine can be guaranteed to observe values produced by writes to the same variable in a different goroutine.
- 翻译过来就是说,Go内存模型通过定义以下的条件,来保证在一个goroutine可以观察到另外的goroutine对这个相同变量的写操作。
Happens Before
在一个goroutine中,读和写的顺序一定是安装程序中的顺序执行的。编译器和处理器只有在不会在改变这个goroutine的行为的时候,才可能修改读和写的执行顺序。
但是由于重排,不同的gouroutine会看到不同的执行顺序。
例如,一个goroutine执行a = 1;b = 2;,另一个goroutine可能看到b在a之前更新。
为了说明读和写的必要性,go引入了Happens Before原语,来对内存模型中指定的条件进行描述。Happens Before翻译过来就是先行发生的意思。
Happens Before的定义:
- 如果事件e1发生在事件e2之前,那么我们说e2发生在事件e1之后。同样,如果e1不发生在e2之前,也不发生在e2之后,那么我们说e1和e2同时发生。
内存模型指定了哪些条件
go的Happens Before定义了2组条件:
第一组条件:
当上面2个条件都满足的时候,对变量v的读操作r是允许对v的写入操作w进行监测的
- r不先行发生于w
- 在w后r前没有对v的其他写操作
第二组条件:
为了确保对变量v的读取操作r能够监测到特定的对v的写操作w, 需要确保w是r允许看到的唯一写操作。即当下面条件满足时,则r能保证监测到w
- w先行发生于r
- 对共享变量v的其它任何写入操作都只能发生在w之前或r之后
在单个goroutine中,这2组条件的定义是一样的。但是,如果在多goroutine的环境下,第二组条件要求会更严格,因为它需要确保没有其他的写入操作与w或者r同时发生
我们看第一组条件,为什么说它没有第二组条件这么严格,r不先行发生于w,并不意味着,r就在w之后,因为它们可以是同时发生。
因此,需要特别注意的是,第一组条件的说法,在2个并发的goroutine来说,一个goroutine能否读到另一个goroutine中写入的数据是不确定的,可能可读到,可能读不到。
第二组条件,由于r发生在w之后,对共享变量v的其它任何写入操作都只能发生在w之前或r之后,意思就是说在r到w这一段期间之间,没有其他的写操作w’,也没有和r并行的写操作w’'发生,所以我们可以说,r读到的值必然是w写入的值。
下面这个图是从go编译语言网站扣过来的:
单Go程的情形:
-- w0 ---- r1 -- w1 ---- w2 ---- r2 ---- r3 ------>
这里不仅是个偏序关系,还是一个良序关系:所有 r/w 的先后顺序都是可比较的。
双Go程的情形:
-- w0 -- r1 -- r2 ---- w3 ---- w4 ---- r5 -------->
-- w1 ----- w2 -- r3 ---- r4 ---- w5 -------->
单Go程上的事件都有先后顺序;而对于两条Go程,情况又有所不同。即便在时间上 r

最低0.47元/天 解锁文章
1288

被折叠的 条评论
为什么被折叠?



