为什么select语句在channel被阻塞时会抛出错误

时间:2021-03-08 04:20:20

标签: go

在此示例中,通道已满,因此 select 语句中的第一个 case 将被阻塞,从而导致打印 default case。或者至少那是我认为应该发生的事情。相反,我收到错误消息“所有 goroutine 都处于睡眠状态 - 死锁!”。为什么是这样?我认为 select 语句会阻塞,直到其中一种情况可以运行,这是本示例中的默认情况。

 func main() {
        c := make(chan int)
        c <- 1
    
        select {
            case c <- 5:
                fmt.Println("a")
            default:
                fmt.Println("only case not blocked")
            // fatal error: all goroutines are asleep - deadlock!
    }
    }

2 个答案:

答案 0 :(得分:2)

执行甚至没有到达 select 语句,因为它在此之前就死锁了。您正在尝试发送到您刚刚创建的频道,但它是无缓冲的 - 无法从中读取任何内容。所以程序死锁,正确地告诉你所有的 goroutines 都被阻塞了。在选择之前删除发送,您将看到预期的行为。

答案 1 :(得分:2)

通道是为 goroutines 通信而设计的。 当一个通道已满时,发送方等待另一个 goroutine 接收它。

无缓冲通道总是满的:必须有另一个 goroutine 来接收发送者发送的内容(同时)。

在这部分中,您写入通道:

c <- 1

这个也写入无缓冲通道,阻塞它:

case c <- 5:

这个例子基于你的代码来展示它是如何工作的:

package main

import (
    "fmt"
    "time"
)

func main() {
    c := make(chan int)
    go func() {
        fmt.Println(<-c) // starting goroutine and continuously reading from chan "c"
    }()

    time.Sleep(time.Millisecond) //to let goroutine start before program ends

    select {
    case c <- 5: // write into the channel so goroutine can read
        fmt.Println("a")
    default:
        fmt.Println("only case not blocked")
    }
    time.Sleep(time.Millisecond) //to let goroutine start before program finishes
}