如何理解golang内存模型中的通道通信规则?

Roy*_*ing 3 channel memory-model go happens-before

在学习golang的过程中,当我试图理解内存模型规范中描述的通道通信时,我有点困惑,如下所示:

  1. 通道上的发送在该通道的相应接收完成之前发生.
  2. 关闭通道发生在返回零值的接收之前,因为通道已关闭.
  3. 来自无缓冲通道的接收在该通道上的发送完成之前发生.
  4. 具有容量C的信道上的第k个接收发生在从该信道发送的第k + Cth个完成之前.

前两条规则清晰且易于理解,而我对第三条规则感到困惑,这似乎与其他规则相反......我是否错过了任何关于无缓冲通道的特殊规定?或者我是否正确如果我像下面的规范中的示例那样:

var c = make(chan int)
var a string

func f() {
    a = "hello, world"
    <-c    // A
}
func main() {
    go f()
    c <- 0 // B
    print(a)
}
Run Code Online (Sandbox Code Playgroud)

对于无缓冲通道,发送操作(B)被阻塞,直到接收器准备好接收值(A)?(比如:B开始并且直到A执行才返回)它准确吗?

我在Effective Go规范中找到了以下陈述,但是我的理解仍然存在差异......那么有人可以用简单直接的方式解释这个吗?

接收器始终阻塞,直到有数据要接收.如果通道未缓冲,则发送方将阻塞,直到接收方收到该值.如果通道有缓冲区,则发送方仅阻塞,直到将值复制到缓冲区为止; 如果缓冲区已满,则表示等待某个接收方检索到某个值.

Tim*_*nes 7

您突出显示的句子是您正在寻找的简单解释.

如果通道未缓冲,则发送方将阻塞,直到接收方收到该值.

这是说点3的另一种方式:

来自无缓冲通道的接收在该通道上的发送完成之前发生.

当您发送无缓冲信道时,发送方将阻塞,直到接收方获取该值.这意味着接收在发送完成之前发生.

缓冲的通道是不同的,因为值已经到了某个地方.如果你仍然感到困惑,一个例子可能会有所帮助:

说我想在你家里留一个包裹:

  • 如果频道是缓冲的,你可以在某个地方离开包 - 也许是邮箱.这意味着我可以在您收到包裹(在通道上发送)(检查邮箱时)完成我的任务.
  • 如果频道没有缓冲,我必须等你的前门,直到你来取走我的包裹.在我完成向您交付的任务之前,您会收到包裹.

对于无缓冲通道,发送操作(B)被阻塞,直到接收器准备好接收值(A)?(比如:B开始并且直到A执行才返回)它准确吗?

是.这是对的.

  • 很好的例子,很有帮助!谢谢! (2认同)