为什么从 nil 通道读取会增加 Goroutines 的数量?

Why does reading from a nil channel increase the number of Goroutines?

我正在阅读此博客,https://medium.com/golangspec/goroutine-leak-400063aef468,并改编了以下示例,说明了由于从 nil 通道接收而导致的 goroutine 泄漏:

package main

import (
    "flag"
    "fmt"
    "runtime"
    "time"
)

var initChannel bool

func main() {
    flag.Parse()

    var ch chan int
    if initChannel {
        ch = make(chan int, 1)
        ch <- 1
    }
    go func(ch chan int) {
        <-ch
    }(ch)

    c := time.Tick(1 * time.Second)
    for range c {
        fmt.Printf("#goroutines: %d\n", runtime.NumGoroutine())
    }
}

func init() {
    flag.BoolVar(&initChannel, "init", false, "initialize channel")
}

我注意到,如果我 运行 它与 initChannel false,goroutines 的数量是 2:

> go run main.go
#goroutines: 2
#goroutines: 2

而如果我 运行 它与 true,则数字是 1:

> go run main.go --init
#goroutines: 1
#goroutines: 1

不过,我不太明白为什么会这样。我只看到一个 go 语句,所以我希望在任何一种情况下都只有一个 goroutine。为什么从 nil 通道读取时有两个 goroutines?

当您的应用程序启动时,已经有一个 goroutine 运行 main() 函数。

如果您不初始化 ch 通道,它将保持其 zero value which is nil for channels. Spec: Receive operator:

Receiving from a nil channel blocks forever.

详情见

所以如果通道是nil,启动的goroutine将永远不会结束。因此,您将有 2 个 goroutine:main goroutine 和您启动的那个。

如果您使用 1 个缓冲区初始化通道并在其上发送一个值,那么对于一个 "short period of time",您还将有 2 个 goroutines,但是启动的 goroutine 可以从中接收一个值,然后立即结束。所以将剩下一个 goroutine,main goroutine。