在Golang中,如何测试一个频道是否接近并且仅在频道未关闭时发送给它?

时间:2016-08-29 18:53:41

标签: go channel

在Golang中,如果频道channel已关闭,我仍然可以使用以下语法从中读取内容,我可以测试ok以查看它是否已关闭。

value, ok := <- channel
if !ok {
    // channel was closed and drained
}

但是,如果我不知道某个频道是否已关闭并盲目写入,我可能会收到错误消息。我想知道是否有任何方法可以测试通道,只有当它没有关闭时才写入它。我问这个问题是因为有时我不知道goroutine中是否关闭了一个频道。

3 个答案:

答案 0 :(得分:15)

你不能。这里的经验法则是只有作者应该关闭频道,这样你知道你不应该再写那个频道了。

一些简单的代码如下所示:

for i := 0; i < 100; i++ {
    value := calculateSomeValue()
    channel <- value
}

close(channel) //indicate that we will no more send values

答案 1 :(得分:4)

如果很少goroutins写入频道,您也可以nil代替close并使用select进行读写。像这样的东西

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")
}

尝试使用https://play.golang.org/p/sp8jk961TB

答案 2 :(得分:0)

不能。您可以拆分将消息发送到通道和从该通道读取的另一个go例程的工作。

您应该添加一个完成的通道,以在阅读器完成时发出信号。

示例。

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