【发布时间】:2018-03-31 01:34:00
【问题描述】:
在学习golang的途中,我在尝试理解内存模型规范中描述的通道通信时有点困惑,如下所示:
- 通道上的发送发生在来自该通道的相应接收完成之前。
- 通道关闭发生在接收返回零值之前,因为通道已关闭。
- 在该通道上的发送完成之前发生来自无缓冲通道的接收。
- 容量为 C 的通道上的第 k 次接收发生在该通道的第 k+C 次发送完成之前。
前两条规则清晰易懂,而我对第三条规则感到困惑,这似乎与其他规则相反......我错过了无缓冲通道的特别之处吗?或者我是正确的吗?如果我按照规范中的示例如下所示:
var c = make(chan int)
var a string
func f() {
a = "hello, world"
<-c // A
}
func main() {
go f()
c <- 0 // B
print(a)
}
对于一个无缓冲的通道,发送操作(B)被阻塞,直到接收者准备好接收值(A)? (如:B 开始,直到 A 执行才返回)准确吗?
我在Effective Go spec 中找到了以下陈述,但与我的理解仍然存在差异......那么有人可以简单直接地解释一下吗?
接收器总是阻塞,直到有数据接收。 如果频道 是无缓冲的,发送方阻塞,直到接收方收到 如果通道有缓冲区,发送方只会阻塞,直到 值已被复制到缓冲区;如果缓冲区已满,这意味着 等到某个接收者检索到一个值。
【问题讨论】:
-
“发生在之前” HB 有一个非常特殊的含义,在线性时间上与传统的“之前”只是松散相关。您可以拥有两个事件
x和y,同时保持两个关系:x HB y和y HB x。规则 1 和 3 一起粗略地说:“在无缓冲通道上发送和接收正确同步并按预期工作(无论 CPU 重新组织指令的方式有多花哨,内存缓存缓存的速度有多快等等。” -
@Volker 嗯...仍然对为什么
x HB y和y HB x都成立感到困惑,哈哈。可能,我需要将事件e拆分为不同的原子阶段,例如开始、处理和结束,以便正确理解这个happens-before术语...谢谢! -
HB 并不意味着某件事实际上发生在比其他事情更早的时间,它只是一个方便的助记符。 HB 图由部分 HB 顺序建立,确定哪些内存操作在哪里可见。这是一个模型而不是现实。 HB 建立的是同步保证。它没有说明实际发生的事情。
-
显然
happens-before一词具有误导性,请参阅此示例play.golang.org/p/1NJrpo-hnjQ... 我发现自己对执行代码如何根据使用通道作为信号进行流动有点困惑。
标签: go channel memory-model happens-before