nil channel VS closed channel


The zero value of channel type is nil, and the send and receive operations on a nil channel will always block. Check the following example:

  1. package main
  2. import "fmt"
  3. func main() {
  4. var ch chan int
  5. go func(c chan int) {
  6. for v := range c {
  7. fmt.Println(v)
  8. }
  9. }(ch)
  10. ch <- 1
  11. }

The running result is like this:

  1. fatal error: all goroutines are asleep - deadlock!
  2. goroutine 1 [chan send (nil chan)]:
  3. main.main()
  4. /root/nil_channel.go:14 +0x64
  5. goroutine 5 [chan receive (nil chan)]:
  6. main.main.func1(0x0)
  7. /root/nil_channel.go:9 +0x53
  8. created by main.main
  9. /root/nil_channel.go:12 +0x37

We can see the main and func goroutines are both blocked.

The Go‘s built-in close function can be used to close the channel which must not be receive-only, and it should always be executed by sender, not receiver. Closing a nil channel will cause panic. See the following example:

  1. package main
  2. func main() {
  3. var ch chan int
  4. close(ch)
  5. }

The running result is like this:

  1. panic: close of nil channel
  2. goroutine 1 [running]:
  3. panic(0x456500, 0xc82000a170)
  4. /usr/local/go/src/runtime/panic.go:481 +0x3e6
  5. main.main()
  6. /root/nil_channel.go:5 +0x1e

Furthermore, there are also some subtleties of operating an already-closed channel:

(1) Close an already channel also cause panic:

  1. package main
  2. func main() {
  3. ch := make(chan int)
  4. close(ch)
  5. close(ch)
  6. }

The running result is like this:

  1. panic: close of closed channel
  2. goroutine 1 [running]:
  3. panic(0x456500, 0xc82000a170)
  4. /usr/local/go/src/runtime/panic.go:481 +0x3e6
  5. main.main()
  6. /root/nil_channel.go:6 +0x4d

(2) Send on a closed channel will also introduce panic:

  1. package main
  2. func main() {
  3. ch := make(chan int)
  4. close(ch)
  5. ch <- 1
  6. }

The running result is like this:

  1. panic: send on closed channel
  2. goroutine 1 [running]:
  3. panic(0x456500, 0xc82000a170)
  4. /usr/local/go/src/runtime/panic.go:481 +0x3e6
  5. main.main()
  6. /root/nil_channel.go:6 +0x6c

(3) Receive on a closed channel will return the zero value for the channel’s type without blocking:

  1. package main
  2. import "fmt"
  3. func main() {
  4. ch := make(chan int)
  5. close(ch)
  6. fmt.Println(<-ch)
  7. }

The executing result is like this:

  1. 0

The following is a summary of “nil channel VS closed channel”:






















Operation type Nil channel Closed channel
Send Block Panic
Receive Block Not block, return zero value of channel’s type
Close Panic Panic

References:
Package builtin;
Is it OK to leave a channel open?;
The Go Programming Language Specification.