I am learning channels in Go by following this tutorial. When I only send value to a channel it gives error. Here is the example code.
package main
import "fmt"
func main() {
ch := make(chan int)
ch <- 1
fmt.Println("Does not work")
}
Here I am just sending value to the channel but not receiving anything. It give an error
fatal error: all goroutines are asleep - deadlock!
But when I run following code it doesn't give any error
package main
import "fmt"
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to c
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
fmt.Println("did not receive but still works")
}
and prints
did not receive but still works
I couldn't understand why it works in second case while it does not work in first case. Even though I have not received any value for the channel in both cases. Also what is causing the deadlock in first case and how it gets avoided in second case?
Neither example works. In fact, no example that only sends to a channel will ever work, in any traditional sense of "work".
But here's a step through of each, to make it clear:
ch := make(chan int)
This creates an unbuffered channel. Unbuffered channels don't hold any data, they only act as a conduit for communication--all data sent must be received by something else, before the program execution proceeds--on either side of the channel.
ch <- 1
Here you send data on the channel, but nothing is waiting to receive it, so the program waits. In this case, it waits forever, because you never created a receiver for the channel, thus your deadlock.
c := make(chan int)
Again, create an unbuffered channel.
go sum(s[:len(s)/2], c)
Call the sum
function, which, incidentally, will also block forever, for the reasons described above--nothing is receiving on the channel, so it will wait forever. However, in this case, you've called it in a goroutine. The goroutine will run in a separate execution thread, while other bits of the program run. Although, due to never receiving data from the channel, this goroutine will never exit, until the main program exits.
go sum(s[len(s)/2:], c)
Again, you call sum
, and again, in a goroutine. So at this point, you have three gorotuines: One running main()
, and one each running an invocation of sum()
. The latter two will never exit.
Then your program exits. When the program exits, all goroutines (including the two that are stuck forever waiting on your channel) exit.
Since this program exits immediately, the deadlock is never reported, but it does assuredly exist, same as in your first example.