concurrency/memory-model/ #6
Replies: 1 comment 1 reply
-
也可以描述成e2 happens after e2 |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
concurrency/memory-model/
内存模型 # Go语言中的内存模型规定了多个goroutine读取变量时候,变量的可见性情况。注意本章节的内存模型并不是内存对象分配、管理、回收的模型,准确的说这里面的内存模型是内存一致性模型。
Happens Before原则 # Happens Before原则的定义是如果一个操作e1先于操作e2发生,那么我们就说e1 happens before e2,也可以描述成e2 happens after e2,此时e1操作的变量结果对e2都是可见的。如果e1操作既不先于e2发生又不晚于e2发生,我们说e1操作与e2操作并发发生。
Happens Before具有传导性:如果操作e1 happens before 操作e2,e3 happends before e1,那么e3一定也 happends before e2。
由于存在指令重排和多核CPU并发访问情况,我们代码中变量顺序和实际方法顺序并不总是一致的。考虑下面一种情况:
a := 1 b := 2 c := a + 1 上面代码中是先给变量a赋值,然后给变量b赋值,最后给编程c赋值。但是在底层实现指令时候,可能发生指令重排:变量b赋值在前,变量a赋值在后,最后变量c赋值。对于依赖于a变量的c变量的赋值,不管怎样指令重排,Go语言都会保证变量a赋值操作 happends before c变量赋值操作。
上面代码运行是运行在同一goroutine中,Go语言时能够保证happends before原则的,实现正确的变量可见性。但对于多个goroutine共享数据时候,Go语言是无法保证Happens Before原则的,这时候就需要我们采用锁、通道等同步手段来保证数据一致性。考虑下面场景:
var a, b int // goroutine A go func() { a = 1 b = 2 }() // goroutine B go func() { if b == 2 { print(a) } }() 当执行goroutine B打印变量a时并不一定打印出来1,有可能打印出来的是0。这是因为goroutine A中可能存在指令重排,先将b变量赋值2,若这时候接着执行goroutine B那么就会打印出来0
https://go.cyub.vip/concurrency/memory-model/
Beta Was this translation helpful? Give feedback.
All reactions