关闭Go中的频道

syn*_*gma 0 channel go

我正在学习通道如何在Go中工作,并且偶然发现了关闭频道的问题.这是来自A Tour of Go的修改示例,它生成n-1个斐波纳契数并通过通道发送它们,使通道容量的最后一个"元素"不被使用.

func fibonacci(n int, c chan int) {
    x, y := 0, 1
    for i := 0; i < n-1; i++ {
        c <- x
        x, y = y, x+y

    }
    // close(c) // It's commented out on purpose
}

func main() {
    n := 10
    c := make(chan int, n)
    go fibonacci(n, c)

    for i := 0; i < n; i++ {
        _, ok := <-c
        fmt.Println(ok)
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我得到:

致命错误:所有goroutines都睡着了 - 僵局!

当我不关闭频道.究竟是什么导致了僵局?当我不关闭它时,为什么我不能从其容量边界的频道接收到它?

hel*_*ert 5

您正在将n个值写入通道(从0到n-1),但是尝试从通道读取n + 1个值(从0到n).如果没有明确关闭通道,main函数将永远等待最后一个值.

究竟是什么导致了僵局?

n次迭代之后,运行该fibonacci函数的goroutine 将退出.在此goroutine退出之后,程序中唯一剩下的goroutine就是maingoroutine,而这个goroutine正在等待将一些数据写入c通道 - 并且由于没有其他goroutine可能会将数据写入此通道,它将永远等待.这正是错误消息试图告诉你的:"所有goroutines("all"只是"一个",这里)都是睡着了".

_, ok := <- c呼叫main功能只会停止为尽快阻断c通道被关闭(如从信道阻塞阅读,这需要从另一个goroutine中进行).当通道关闭时,该main功能将从通道读取剩余数据(当它是缓冲通道时)