使用异常选择的意外行为

我正在编写一些代码,将数据从一个通道传递到另一个通道。遵循一些直觉和这个答案,我希望以下代码能够工作(other是一个足够大的缓冲通道并且out是源通道):


for {

    select {

    case other <- (<-out):

        log.Warn("C")

    }

}

确实如此!但其他情况根本不会触发,例如日志中没有Ds 用于以下代码:


for {

    select {

    case other <- (<-out):

        log.Warn("C")

    default:

        log.Warn("D")

    }

}

使用更传统的解决方案,D日志中到处都是 s:


for {

    select {

    case msg := <-out:

        other <- msg

        log.Warn("C")

    default:

        log.Warn("D")

    }

}

显然,我将使用通常的解决方案,但我仍然不知道为什么不寻常的解决方案无法按预期工作。


我怀疑答案在Go Memory Model 中的某个地方,但我无法完全弄清楚在这种情况下到底发生了什么。


我整理了一些游乐场,您可以在其中查看此行为:


Unusal(根本没有Ds)

通常(有很多Ds,您可能必须在本地尝试才能看到除Ds之外的任何内容)

提前感谢任何可以对此有所了解的人!


Smart猫小萌
浏览 151回答 1
1回答

叮当猫咪

当你有这个:ch := make(chan int, 10)// ...select {case ch <- <-out:&nbsp; &nbsp; fmt.Println("C")default:&nbsp; &nbsp; fmt.Println("D")}第一个的通信操作case是ch <- something,哪里something是<-out。但是something首先评估,然后才检查案例的哪些通信操作可以进行。所以<-out只要它需要就会阻塞,然后ch <- something检查它是否可以继续。由于您使用了足够大的缓冲区,因此它始终可以在您的示例中继续进行,因此default永远不会选择。规范:选择语句:“select”语句的执行分几个步骤进行:对于语句中的所有情况,在输入“select”语句时,接收操作的通道操作数以及发送语句的通道和右侧表达式仅按源顺序计算一次。结果是一组要接收或发送到的通道,以及要发送的相应值。无论选择哪种(如果有的话)通信操作进行,该评估中的任何副作用都会发生。RecvStmt 左侧的带有短变量声明或赋值的表达式尚未计算。如果一个或多个通信可以进行,则通过统一的伪随机选择选择一个可以进行的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。除非所选案例是默认案例,否则执行相应的通信操作。如果所选案例是带有短变量声明或赋值的 RecvStmt,则计算左侧表达式并分配接收到的值(或多个值)。执行所选案例的语句列表。如果你降低 的缓冲区ch,你会看到偶尔在输出中打印 s(在Go PlaygroundD上试试)。ch&nbsp;:=&nbsp;make(chan&nbsp;int,&nbsp;2)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go