我正在学习通道如何在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)
}
}
问题是我得到了:
致命错误:所有goroutine都睡着了 - 死锁!
当我不关闭频道时。究竟是什么导致了僵局?当我不关闭它时,为什么我无法从通道的容量边界收到它?
答案 0 :(得分:5)
您正在将 n 值写入通道(从0到 n-1 ),但正在尝试读取 n + 1 通道中的值(从0到 n )。如果没有明确关闭通道,main
函数将永远等待最后一个值。
究竟是什么导致了僵局?
在 n 迭代之后,运行fibonacci
函数的goroutine将退出。在此goroutine退出之后,程序中唯一剩下的goroutine是main
goroutine,而这个goroutine正在等待将一些数据写入c
通道 - 并且因为没有其他goroutine离开那可能会将数据写入此频道,它将永远等待。这正是错误消息试图告诉您的内容:“所有goroutines (”all“只是”one“,这里)睡着了”。
_, ok := <- c
函数中的main
调用只会在c
频道关闭时停止阻止(因为从频道读取阻止,这需要从另一个频道完成够程)。当通道关闭时,main
功能将从通道读取剩余数据(当它是缓冲通道时)
答案 1 :(得分:0)
对于主要期望在通道中进行n次通信的循环,但是在func fibonacci中只产生n-1
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ { //here
c <- x
x, y = y, x+y
}
// close(c) // It's commented out on purpose
}