Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test if a channel is close and only send to it when it's not closed

Tags:

go

channel

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.

like image 597
Just a learner Avatar asked Aug 29 '16 18:08

Just a learner


People also ask

What happens when channel is closed 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.

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.

Do you need to close channels?

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 if a channel is closed or not?

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

How do I Close a channel?

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.

Should I stop sending values to a channel if it returns false?

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 .

When should we close a channel in a sender goroutine?

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.)


3 Answers

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
like image 85
serejja Avatar answered Oct 19 '22 15:10

serejja


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

like image 10
Uvelichitel Avatar answered Oct 19 '22 16:10

Uvelichitel


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

like image 1
Hace Avatar answered Oct 19 '22 16:10

Hace