Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Go panic on writing to a closed channel?

Tags:

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?

like image 288
Everton Avatar asked Jan 20 '16 10:01

Everton


People also ask

What happens if you write to a closed channel Golang?

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.

What happens when a channel is closed?

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.

What happens if you close a closed channel Golang?

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.

How do I gracefully close a channel?

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.


1 Answers

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

like image 125
Justlike Avatar answered Oct 10 '22 02:10

Justlike