为了账号安全,请及时绑定邮箱和手机立即绑定

选择语句的细微差别

选择语句的细微差别

Go
饮歌长啸 2021-08-16 18:56:12
我阅读了 select 语句及其执行步骤,但我并不完全理解这里发生了什么。我创建了两个扇入函数示例(来自Go Concurrency Patterns talk)第一个:select {case value := <-g1:    c <- valuecase value := <-g2:    c <- value}按预期从每个通道打印(每个通道都有自己的计数器):Bob  : 0Alice: 0Bob  : 1Alice: 1Bob  : 2Alice: 2Alice: 3Alice: 4Bob  : 3Alice: 5第二个:select {case c <- <-g1:case c <- <-g2:}它随机选择一个通道并丢弃另一个通道的值:Bob  : 0Alice: 1Alice: 2Alice: 3Bob  : 4Alice: 5Bob  : 6Alice: 7Alice: 8Bob  : 9更新:在写这个问题时,我认为第二个select 等于:var v stringselect {case v = <-g1:case v = <-g2:    c <- v}但我错了,因为这个总是从第二个通道打印(正如 switch like 语句所预期的那样,因为 select 语句中没有fallthrough):Bob  : 0Bob  : 1Bob  : 2Bob  : 3Bob  : 4Bob  : 5Bob  : 6Bob  : 7Bob  : 8Bob  : 9有人明白为什么我的第二个例子会创建一个序列吗?
查看完整描述

2 回答

?
四季花海

TA贡献1811条经验 获得超5个赞

您的第二个选择语句被解释为:


v1 := <-g1

v2 := <-g2

select {

case c <- v1:

case c <- v2:

}

如语言规范中所述,每个发送运算符的 RHS 将在执行语句时预先评估:


“select”语句的执行分几个步骤:


对于语句中的所有情况,接收操作的通道操作数以及发送语句的通道和右侧表达式在进入“选择”语句时按源顺序被计算一次。结果是一组要接收或发送的通道,以及要发送的相应值。无论选择哪个(如果有)通信操作进行,该评估中的任何副作用都会发生。带有简短变量声明或赋值的 RecvStmt 左侧的表达式尚未计算。

如果可以进行一个或多个通信,则通过统一伪随机选择选择可以进行的单个通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。

...

因此,作为步骤(1),<-g1和<-g2都将被评估,从每个通道接收值。如果还没有什么可接收,这可能会阻塞。


在 (2) 处,我们等待直到c准备好发送一个值,然后随机选择 select 语句的一个分支来执行:因为它们都在同一个通道上等待,所以它们都准备好继续。


这解释了您在值被丢弃的地方看到的行为,以及您在将值发送到c.


如果您想等待g1和g2,您将需要使用您发现的报表的第一种形式。


查看完整回答
反对 回复 2021-08-16
  • 2 回答
  • 0 关注
  • 173 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信