Go通道写入顺序保证

huangapple go评论64阅读模式
英文:

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 可能会先执行吗?

是否有任何参考资料可以验证这种行为在文档/代码中?

英文:

Given the following code:

ch1 := make(chan struct{}, 1)
ch2 := make(chan struct{})
ready := make(chan struct{})
done := make(chan struct{})

go func() {
    close(ready)
    select {
    case &lt;-ch1:
        fmt.Println(&quot;ch1&quot;)
    case &lt;-ch2:
        fmr.Println(&quot;ch2&quot;)
    }
}()

&lt;-ready

ch1 &lt;- struct{}{}
close(ch2)

&lt;-done

Is it guaranteed to always print "ch1"? Or is it possible that since the ch1 is buffered and ch2 is closed right after, the second case could run first?

And is there any reference to verify this behavior in the documentation / code?

答案1

得分: 1

写入ch1不会立即导致选择操作继续进行。在通道写入或关闭操作之后,可以调度goroutine,因此两种情况都有机会运行。如果ch1是无缓冲的,则写操作只会在通道读取之后发生,因此程序将始终打印ch1。

英文:

Writing to ch1 will not immediately cause the select operation to continue. The goroutine can be scheduled after the channel write or after the close operation so both cases have a chance to run. If ch1 was unbuffered then write operation would only happen after channel read so the program would always print ch1.

答案2

得分: 1

不,不能保证第二种情况不会发生。

当你使用通道时,通道是用于同步两个 goroutine 的理想工具,但你在操作两个独立的通道。因此,不能保证主 goroutine 对非缓冲的 ch1 通道的写操作会立即让出控制权给第二个 goroutine 的 select 语句。

在调度器将控制权让给其他 goroutine 之前,ch2 的关闭操作也可能发生,然后一个具有两个可能路径的 select 语句将随机选择。

个别证据可能让人想要相信,但在不同的负载条件下,这会导致危险的假设。


查看早期的Go调度器设计文档对于理解调度器的实现细节并没有太大帮助,因为 Go 语言的每个版本发布时,调度器的实现细节都会发生变化。

总之,需要在两个独立通道之间进行协调,以确保处理顺序的任何保证。

英文:

No, there is no guarantee that the second case may not occur.

While you are using channels - and channels are ideal for synchronizing two goroutines - you are manipulating two separate channels. So there is no guarantee that the main goroutine's write to an unbuffered ch1 channel will immediately yield control over to the second goroutine's select statement.

The close of ch2 may also occur before the scheduler yields control to other goroutines - and then a select with two possible paths, will be chosen at random.

Anectodal evidence may be tempting to believe, but will lead to dangerous assumptions under different load conditions.


Looking at an early doc for the Go Scheduler Design doc will not be of much help as the implementation details of the schedule will literally change from release to release of the Go language.

In closing, coordination between the two independent channels is needed to make any guarantees of the processing order.

huangapple
  • 本文由 发表于 2021年10月6日 06:11:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/69457790.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定