为什么我的 `for-select` 语句即使在我关闭它后仍继续从我的频道接收?

Why does my `for-select` statement keeps receiving from my channel even after I close it?

我有以下代码:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    ch2 := make(chan int)
    go func(c chan int, c2 chan int) {
        for {
            select {
            case v := <-c:
                fmt.Println(v)
            case v := <-c2:
                fmt.Println(v)
            default:
            }
        }
    }(ch, ch2)
    ch <- 1
    close(ch)
    close(ch2)
    time.Sleep(10 * time.Second)
}

当我运行这个时,它打印1到stdout,然后继续打印0。这是为什么?

我知道我可以在我的 goroutine 中检查通道是否关闭,但我只想知道关闭的原因。

此外,假设我想在所有(多个)通道关闭后退出 goroutine,这可能吗?我假设一旦所有通道都关闭,在默认情况下,我可能会在所有通道关闭后退出 goroutine

这是每个 Spec: Receive operator:

的预期行为

A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.

如果您想在从通道接收到所有值(在通道关闭之前发送到通道上)后终止循环,请使用 for ... range 结构,例如:

c := make(chan int) // Initialize some channel

for v := range c {
    fmt.Println("Received:", v)
}

如果你有多个频道并且你想从所有频道接收,你可以使用多个 goroutines,每个 goroutines 都有一个 for range 用于指定的频道。

另一个解决方案是:

A function can read from multiple inputs and proceed until all are closed by multiplexing the input channels onto a single channel that's closed when all the inputs are closed. This is called fan-in.

Go 博客中阅读更多相关信息 Go 并发模式:管道和取消:Fan-out-fain-in.

The Go Programming Language Specification

Close

After calling close, and after any previously sent values have been received, receive operations will return the zero value for the channel's type without blocking.

Receive operator

A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.