Out of 3 code snippets, the one with channels declared in local scope works, other code snippets gives deadlock issue, One of the previously answered SO question here says try to avoid declaring channel in the global scope. I checked in the official docs, but I didn't find any explanation.
Why is the global scope channel giving an error although I am not blocking the channel from sending and receiving? why am I getting a deadlock issue here?
How is make(chan int)
different from var myChan chan int
except in terms of scope and initialization?
Can anyone explain and suggest better articles/documents/links/pdfs to effectively use channels(and implement concurrency) in Go?
(imports and 'package main' is omitted from snippets for purpose of brevity)
// 1. channel declared in global scope
var c chan int
func main(){
go send()
fmt.Println(<-c)
}
func send(){
c <- 42
}
//output: fatal error: all goroutines are asleep - deadlock!
// 2. channel declared in global scope + sending channel to goroutine
var c chan int
func main(){
go send(c)
fmt.Println(<-c)
}
func send(c chan int){
c <- 42
}
//output: fatal error: all goroutines are asleep - deadlock!
// 3. using channel as local scope and sharing it with goroutine
func main(){
c := make(chan int)
go send(c)
fmt.Println(<-c)
}
func send(c chan int){
c <- 42
}
Because by declaring an uninitialized var c chan int
, c
has its type's zero value, which in case of a chan
is nil
.
If you actually run your code, the error message reveals this information. Both goroutines are sending/receiving on a nil
chan:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive (nil chan)]:
main.main()
/tmp/sandbox288806111/prog.go:11 +0x5c
goroutine 18 [chan send (nil chan)]:
main.send()
/tmp/sandbox288806111/prog.go:15 +0x39
created by main.main
/tmp/sandbox288806111/prog.go:10 +0x39
With make
instead you are explicitly initializing the variable c
, which is then not nil
.
This has nothing to do with the global scope per-se. In fact if you properly initialize the variable, e.g. var c chan int = make(chan int)
, even in the global scope, the program won't deadlock.
Additional readings: channel axioms (Dave Cheney)
If the channel is nil then the sender and receiver have no reference to each other; they are both blocked waiting on independent channels and will never unblock.