Why does Go panic on writing to a closed channel?
While one can use the value, ok := <-channel
idiom for reading from channels, and thus the ok result can be tested for hitting a closed channel:
// reading from closed channel package main import "fmt" func main() { ch := make(chan int, 1) ch <- 2 close(ch) read(ch) read(ch) read(ch) } func read(ch <-chan int) { i,ok := <- ch if !ok { fmt.Printf("channel is closed\n") return } fmt.Printf("read %d from channel\n", i) }
Output:
read 2 from channel channel is closed channel is closed
Run "reading from closed channel" on Playground
Writing to a possibly closed channel is more convoluted, because Go will panic if you simply try to write when the channel is closed:
//writing to closed channel package main import ( "fmt" ) func main() { output := make(chan int, 1) // create channel write(output, 2) close(output) // close channel write(output, 3) write(output, 4) } // how to write on possibly closed channel func write(out chan int, i int) (err error) { defer func() { // recover from panic caused by writing to a closed channel if r := recover(); r != nil { err = fmt.Errorf("%v", r) fmt.Printf("write: error writing %d on channel: %v\n", i, err) return } fmt.Printf("write: wrote %d on channel\n", i) }() out <- i // write on possibly closed channel return err }
Output:
write: wrote 2 on channel write: error writing 3 on channel: send on closed channel write: error writing 4 on channel: send on closed channel
Run "writing to closed channel" on Playground
As far as I know, there is not a simpler idiom for writing into a possibly closed channel without panicking. Why not? What is the reasoning behind such an asymmetric behavior between read and write?
If you write to a closed channel, your program will panic (see http://play.golang.org/p/KU7MLrFQSx for example). You could potentially catch this error with recover , but being in a situation where you don't know whether the channel you are writing to is open is usually a sign of a bug in the program.
Closing a channel indicates that no more values will be sent on it. This can be useful to communicate completion to the channel's receivers.
We can close a channel in Golang with the help of the close() function. Once a channel is closed, we can't send data to it, though we can still read data from it. A closed channel denotes a case where we want to show that the work has been done on this channel, and there's no need for it to be open.
The Channel Closing Principle One general principle of using Go channels is don't close a channel from the receiver side and don't close a channel if the channel has multiple concurrent senders. In other words, we should only close a channel in a sender goroutine if the sender is the only sender of the channel.
From the Go Language Spec:
For a channel c, the built-in function close(c) records that no more values will be sent on the channel. It is an error if c is a receive-only channel. Sending to or closing a closed channel causes a run-time panic. Closing the nil channel also causes a run-time panic. After calling close, and after any previously sent values have been received, receive operations will return the zero value for the channel's type without blocking. The multi-valued receive operation returns a received value along with an indication of whether the channel is closed.
If you write to a closed channel, your program will panic. You could potentially catch this error with recover if you really want to do that, but being in a situation where you don't know whether the channel you are writing to is open is usually a sign of a bug in the program.
Some quotes:
Here is a motivation:
A channel "close" is really just a send of a special value on a channel. It is a special value that promises that no more values will be sent. Attempting to send a value on a channel after it has been closed will panic, since actually sending the value would violate the guarantee provided by close. Since a close is just a special kind of send, it is also not permitted after the channel has been closed.
Here is another:
The only use of channel close is to signal to the reader that there are no more values to come. That only makes sense when there is a single source of values, or when multiple sources coordinate. There is no reasonable program in which multiple goroutines close a channel without communicating. That would imply that multiple goroutines would know that there are no more values to send--how could they determine that if they don't communicate?
(Ian Lance Taylor)
--
Here is another:
Closing a channel releases it as a resource. It makes no more sense to close a channel multiple times than it makes to close a file descriptor multiple times, or free a block of allocated memory multiple times. Such actions imply the code is broken, which is why closing a closed channel triggers a panic.
(Rob Pike)
--
Source: Go design detail rationale question - channel close
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With