golang channel happens before原则

61 阅读1分钟
  • 对一个元素的send操作Happens Before对应的receive 完成操作
  • 对channel的close操作Happens Before receive 端的收到关闭通知操作
  • 对于Unbuffered Channel,对一个元素的receive 操作Happens Before对应的send完成操作
  • 对于Buffered Channel,假设Channel 的buffer 大小为C,那么对第k个元素的receive操作,Happens Before第k+C个send完成操作。 可以看出上一条Unbuffered Channel规则就是这条规则C=0时的特例 注意:对于Buffered Channel不能保证一个元素的receive操作Happens Before对应的send完成操作

Happens Before receive/send完成操作指在receive/send下一条操作之前完成。不是指在receive/send之前完成。如下面的例子:执行到<-c语句并不代表receive完成,而执行到print(a)则可保证receive已经完成。

var c = make(chan int, 10)
var a string

func f() {
	a = "hello, world"
	c <- 0
}

func main() {
	go f()
	<-c
	print(a)
}

保证输出hello,world。原因 c<-0(send操作) happedns before print(a)(receive完成操作) 对a的写入必定在c<-0的前面。打印a必定在<-c的后面。所以保证输出hello,world。

// Channel routine 2
var c = make(chan int, 10)
var a string

func f() {
	a = "hello, world"
	<-c
}
func main() {
	go f()
	c <- 0
	print(a)
}

由于Buffered Channel不能保证一个元素的receive操作Happens Before对应的send完成操作,因此不能保证<-c(receive操作) Happens Before print(a)(send完成操作),即不能保证对a的写入在print(a)的前面。所以可能会打印empty string

// Channel routine 1
var c = make(chan int)
var a string

func f() {
	a = "hello, world"
	<-c
}
func main() {
	go f()
	c <- 0
	print(a)
}

<- c(receive操作) happens before print(a)(send完成操作),所以可以保证打印hello,world。