Go 内存模型描述的是 “在一个 groutine 中对变量进行读操作能够侦测到在其他 gorountine 中对改变量的写操作” 的条件。
To specify the requirements of reads and writes, we define happens before, a partial order on the execution of memory operations in a Go program. If event e1 happens before event e2, then we say that e2 happens after e1. Also, if e1 does not happen before e2 and does not happen after e2, then we say that e1 and e2 happen concurrently.
这是 Happens Before
的定义,如果 e1 发生在 e2 之前,那么我们就说 e2 发生在 e1 之后,如果 e1 既不在 e2 前,也不在 e2 之后,那我们就说这俩是并发的.
关于channel的happens-before在Go的内存模型中提到了三种情况:
测试代码:
import "testing"
var c = make(chan int, 10)
var a string
func f() {
a = "hello, world" // (1)
c <- 0 // (2) 写操作 发送操作
}
func TestMemoryModel(t *testing.T) {
go f()
<-c // (3) //接收操作
print(a) // (4)
}
上面的代码,将保证会打印出 hello world
。有缓冲 channel 写操作发生在接收操作之前。
var c1 = make(chan int)
var a1 string
func f1() {
a1 = "hello, world" // (1)
<-c1 // (2) 接收操作
}
func TestMemoryModel1(t *testing.T) {
go f1()
c1 <- 0 // (3) 发送操作
print(a1) // (4)
}
运行结果:
=== RUN TestMemoryModel1
hello, world--- PASS: TestMemoryModel1 (0.00s)
PASS
上面的代码将保证会打印出 hello world
。因为
根据上面的第三条规则(2) happens-before (3),最终可以保证(1) happens-before (4)。
无缓冲 channel
接收操作发生在写操作之前。
var c2= make(chan int, 1)
var a2 string
func f2() {
a2 = "hello, world" // (1)
<-c2 // 接收操作
}
// 不能保证 打印出 "hello, world"
func TestMemoryModel2(t *testing.T) {
go f2()
c2 <- 0 // (3)
print(a2) // (4) 写操作
//var day time.Time
//print(day.Format("20060102"))
}
上面的代码不能保证打印出 hello world
, 因为输出的channel 是有缓冲的,不能保证接收操作发生在写操作之前,但是能保证写操作发生在接收操作之前。
公众号:程序员财富自由之路
博客:CSDN 王小明
关注我们,了解更多
关注后:回复 “idea” 或者 “内推”, 有惊喜