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
的分数是c
,Expression
的分数是<-chan_never_used
。
因此,select
发送语句的(可能)非阻塞的语义不适用,因为它是阻塞的表达式。在应用发送语句语义之前,必须完全评估表达式部分。
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
的分数是c
,Expression
的分数是<-chan_never_used
。
因此,select
发送语句的(可能)非阻塞的语义不适用,因为它是阻塞的表达式。在应用发送语句语义之前,必须完全评估表达式部分。