Select 在 time.After 结果死锁

Select on time.After results deadlock

package main

import "time"

func main() {
    chan_never_used := make(chan int, 10)

    c := make(chan int, 10)
    for {
        select {
        case <-time.After(time.Second):
            c <- 0
        case c <- <-chan_never_used:
        }

        println(<-c)
    }
}

https://play.golang.org/p/7hZMdITecg

上面的代码导致 fatal error: all goroutines are asleep - deadlock!

但是如果我换一行:

package main

import "time"

func main() {
    chan_never_used := make(chan int, 10)

    c := make(chan int, 10)
    for {
        select {
        case <-time.After(time.Second):
            c <- 0
        case n := <-chan_never_used: // This line changed
            c <- n                   // Add this line
        }

        println(<-c)
    }
}

效果很好。

为什么第一个版本的代码会导致死锁,为什么这个更改能让代码工作?

根据 select statement contains of a bunch of Send or Receive 语句的标准。

在本例中是发送语句。

发送语句定义为:

SendStmt = Channel "<-" Expression .
Channel  = Expression .

查看您的代码:

case c <- <-chan_never_used:

Channel的分数是cExpression的分数是<-chan_never_used

因此,select 发送语句的(可能)非阻塞的语义不适用,因为它是阻塞的表达式。在应用发送语句语义之前,必须完全评估表达式部分。