我读到了关于select语句及其执行步骤,但我还没有完全理解这里发生了什么。
我创建了两个Fan-In函数示例(来自Go Concurrency Patterns talk)
select {
case value := <-g1:
c <- value
case value := <-g2:
c <- value
}
按预期从每个频道打印(每个频道都有自己的计数器):
Bob : 0
Alice: 0
Bob : 1
Alice: 1
Bob : 2
Alice: 2
Alice: 3
Alice: 4
Bob : 3
Alice: 5
select {
case c <- <-g1:
case c <- <-g2:
}
它随机选择一个频道并丢弃另一个频道:
Bob : 0
Alice: 1
Alice: 2
Alice: 3
Bob : 4
Alice: 5
Bob : 6
Alice: 7
Alice: 8
Bob : 9
更新:在撰写此问题时,我想到了第二个select
was equal to:
var v string
select {
case v = <-g1:
case v = <-g2:
c <- v
}
但我错了,因为这个总是从第二个频道打印(正如预期的那样,从语句开关,因为select语句没有落后):
Bob : 0
Bob : 1
Bob : 2
Bob : 3
Bob : 4
Bob : 5
Bob : 6
Bob : 7
Bob : 8
Bob : 9
是否有人理解为什么我的第二个示例会创建序列?
谢谢,
答案 0 :(得分:4)
您的第二个选择语句被解释为:
v1 := <-g1
v2 := <-g2
select {
case c <- v1:
case c <- v2:
}
As described in the language spec,执行语句时,将预先评估每个发送操作符的RHS:
执行&#34;选择&#34;声明分几步进行:
- 对于语句中的所有情况,接收操作的通道操作数以及发送语句的通道和右侧表达式在输入&#34; select&#34;之后按源顺序精确评估一次。声明。结果是一组要接收或发送的通道,以及要发送的相应值。无论选择哪种(如果有的话)通信操作进行,评估中的任何副作用都将发生。尚未评估具有短变量声明或赋值的RecvStmt左侧的表达式。
- 如果一个或多个通信可以继续,则可以通过统一的伪随机选择来选择可以继续的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,&#34;选择&#34;语句阻塞,直到至少有一个通信可以继续。
- ...
醇>
因此,步骤(1)将评估<-g1
和<-g2
,从每个频道接收值。如果还没有什么东西可以接收,这可能会阻止。
在(2),我们等到c
准备发送一个值,然后随机选择要执行的select语句的一个分支:因为它们都在同一个通道上等待,所以它们都准备好了继续进行。
这解释了您看到的值被删除的行为,并且您获得了将值发送到c
的非确定性行为。
如果您想等g1
和g2
,则需要使用您发现的第一个表单。
答案 1 :(得分:1)
根据[http://golang.org/ref/spec] Go编程语言规范
for { // send random sequence of bits to c
select {
case c <- 0: // note: no statement, no fallthrough, no folding of cases
case c <- 1:
}
}
它将随机生成0或1。
第二次演出
select {
case c <- <-g1:
case c <- <-g2:
}
当g1有Bob : 0
且g2有Alice: 0
时,c <- <-g1
或c <- <-g2
将会执行,但只有一个会执行。
这解释了为什么你有序列0 1 2 3 4 5 6 7 8 9
而不是0 0 1 1 2 2 3 3 4 4
它还说:
in source order, upon entering the "select" statement. The result is a set of channels to receive from or send to, and the corresponding values to send.
根据我的理解,即使c <- <-g1
将执行,Alice: 0
也会从g2弹出。因此,每次有Bob : i
和Alice: i
时,只会打印出一个。