Reputation: 24314
I am learning how channels work in Go and have stumbled upon a problem with closing the channels. This is a modified example from A Tour of Go, which generates n-1 fibonacci numbers and sends them through the channels, leaving the last "element" of the channel capacity unused.
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)
}
}
The problem is that I get:
fatal error: all goroutines are asleep - deadlock!
when I do not close the channel. What exactly is causing the deadlock? Why can't I receive from the channel in its capacity boundaries when I don't close it?
Upvotes: 0
Views: 3005
Reputation: 37964
You're writing n values into the channel (from 0 to n-1), but are trying to read n+1 values from the channel (from 0 to n). Without explicitly closing the channel, the main
function will wait forever for this last value.
What exactly is causing the deadlock?
After n iterations, the goroutine running the fibonacci
function will exit. After this goroutine has exited, the only remaining goroutine in your program is the main
goroutine, and this goroutine is waiting for some data to be written to the c
channel -- and since there is no other goroutine left that might ever write data into this channel, it will wait forever. This is exactly what the error message is trying to tell you: "all goroutines ("all" is just "one", here) are asleep".
The _, ok := <- c
call in the main
function will only stop blocking as soon as the c
channel is closed (as reading from a channel is blocking, this needs to be done from another goroutine). When the channel is closed, the main
function will read remaining data from the channel (when it's a buffered channel)
Upvotes: 5
Reputation: 8490
For loop in main expect n communication in channel, but you produce only n-1 in func fibonacci
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
}
should work http://play.golang.org/p/zdRuy14f9x
Upvotes: 0