In Go, if a channel channel
is closed, I can still read from it using the following syntax and I can test ok
to see if it's closed.
value, ok := <- channel
if !ok {
// channel was closed and drained
}
However, if I don't know whether a channel is closed and blindly write to it, I may got an error. I want to know if there is any way that I can test the channel and only write to it when it's not closed. I ask this question is because sometimes I don't know if a channel is closed or not in a goroutine.
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.
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.
You needn't close every channel when you've finished with it. It's only necessary to close a channel when it is important to tell the receiving goroutines that all data have been sent.
How to check a channel is closed or not without reading it? You can't. The rule of thumb here is that only writers should close channels, this way you know that you shouldn't write to that channel anymore. for i := 0; i < 100; i++ { value := calculateSomeValue () channel <- value } close (channel) //indicate that we will no more send values
A channel may be closed with the built-in function close. The multi-valued assignment form of the receive operator reports whether a received value was sent before the channel was closed.
Although it is okay to stop sending values to a channel ch if the call closed (ch) returns true , it is not safe to close the channel or continue sending values to the channel if the call closed (ch) returns false .
In other words, we should only close a channel in a sender goroutine if the sender is the only sender of the channel. (Below, we will call the above principle as channel closing principle.)
You can't. The rule of thumb here is that only writers should close channels, this way you know that you shouldn't write to that channel anymore.
Some simple code would look like this:
for i := 0; i < 100; i++ {
value := calculateSomeValue()
channel <- value
}
close(channel) //indicate that we will no more send values
If few goroutins write to channel you can also nil
it instead of close
and use select
to read and write. Something like this
ch := make(chan int, 1)
var value int
ch <- 5
select {
case value = <-ch:
fmt.Println("value", value)
default:
fmt.Println("oops")
}
ch = nil
select {
case ch <- 5:
default:
fmt.Println("don't panic")
}
select {
case value = <-ch:
fmt.Println("value", value)
default:
fmt.Println("oops")
}
Try it works https://play.golang.org/p/sp8jk961TB
You can't. You could split up the work where messages are sent to a channel and another go routine that reads from a channel.
You should could add a donechannel to signal when the reader is done.
Example.
package main
import (
"fmt"
)
func main() {
mychan := make(chan int)
donechannel := make(chan struct{})
go pushchannel(mychan)
go drainchan(mychan, donechannel)
_, ok := <-donechannel; if !ok {
fmt.Println("can not read from donechannel this means donechannel is closed, means we are done :)")
}
fmt.Println("Done")
}
func pushchannel(ch chan int) {
fmt.Println("pushing to chan")
for i:=0; i<=10; i++ {
fmt.Printf("pushed %v\n",i)
ch<-i
}
close(ch)
}
func drainchan(ch chan int, donechannel chan struct{}) {
fmt.Println("draining")
for {
res, ok := <- ch
if !ok {
fmt.Println("result channel is closed, we can signal the donechannel now.")
close(donechannel)
break
} else {
fmt.Printf("got result %v\n", res)
}
}
}
https://play.golang.org/p/BMyMkrqWF7s
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