Go 通道写入顺序保证
Go channel write ordering guarantees
给定以下代码:
ch1 := make(chan struct{}, 1)
ch2 := make(chan struct{})
ready := make(chan struct{})
done := make(chan struct{})
go func() {
close(ready)
select {
case <-ch1:
fmt.Println("ch1")
case <-ch2:
fmr.Println("ch2")
}
}()
<-ready
ch1 <- struct{}{}
close(ch2)
<-done
是否保证始终打印“ch1”?或者是否有可能因为 ch1
被缓冲并且 ch2
立即关闭,第二个 case
可以先 运行?
文档/代码中是否有任何参考来验证此行为?
写入 ch1 不会立即导致 select 操作继续。 goroutine 可以在通道写入之后或关闭操作之后进行调度,因此这两种情况都有机会 运行。如果 ch1 是无缓冲的,那么写入操作只会在通道读取之后发生,因此程序将始终打印 ch1。
不,不能保证第二种情况不会发生。
当您使用通道时——通道是同步两个 goroutine 的理想选择——您正在操作两个独立的通道。所以不能保证主 goroutine 对无缓冲 ch1
通道的写入会立即将控制权交给第二个 goroutine 的 select 语句。
ch2
的关闭也可能发生在调度程序将控制权交给其他 goroutine 之前 - 然后 select
将随机选择两个可能的路径。
可能很容易相信,但在不同的负载条件下会导致危险的假设。
查看 Go Scheduler Design doc 的早期文档不会有太大帮助,因为时间表的实施细节会随着 Go
语言的发布而发生变化。
最后,需要两个独立通道之间的协调来保证处理顺序。
给定以下代码:
ch1 := make(chan struct{}, 1)
ch2 := make(chan struct{})
ready := make(chan struct{})
done := make(chan struct{})
go func() {
close(ready)
select {
case <-ch1:
fmt.Println("ch1")
case <-ch2:
fmr.Println("ch2")
}
}()
<-ready
ch1 <- struct{}{}
close(ch2)
<-done
是否保证始终打印“ch1”?或者是否有可能因为 ch1
被缓冲并且 ch2
立即关闭,第二个 case
可以先 运行?
文档/代码中是否有任何参考来验证此行为?
写入 ch1 不会立即导致 select 操作继续。 goroutine 可以在通道写入之后或关闭操作之后进行调度,因此这两种情况都有机会 运行。如果 ch1 是无缓冲的,那么写入操作只会在通道读取之后发生,因此程序将始终打印 ch1。
不,不能保证第二种情况不会发生。
当您使用通道时——通道是同步两个 goroutine 的理想选择——您正在操作两个独立的通道。所以不能保证主 goroutine 对无缓冲 ch1
通道的写入会立即将控制权交给第二个 goroutine 的 select 语句。
ch2
的关闭也可能发生在调度程序将控制权交给其他 goroutine 之前 - 然后 select
将随机选择两个可能的路径。
查看 Go Scheduler Design doc 的早期文档不会有太大帮助,因为时间表的实施细节会随着 Go
语言的发布而发生变化。
最后,需要两个独立通道之间的协调来保证处理顺序。