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

Jus*_*ner 18 channel go

在Golang中,如果某个频道channel已关闭,我仍然可以使用以下语法从中读取它,我可以测试ok它是否已关闭.

value, ok := <- channel
if !ok {
    // channel was closed and drained
}
Run Code Online (Sandbox Code Playgroud)

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

ser*_*jja 20

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

一些简单的代码看起来像这样:

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

close(channel) //indicate that we will no more send values
Run Code Online (Sandbox Code Playgroud)

  • 如果多个goroutine写入同一个频道怎么办?如果一个goroutine已完成其工作,它不能简单地关闭频道.其他goroutine可能仍需要写入频道. (4认同)
  • @OgrishMan:当你完成所有goroutine时,你有一个外部观察者关闭通道,或者根本不关闭它. (4认同)
  • @OgrishMan 在此答案中使用“sync.WaitGroup”查看解决方案:[关闭未知长度的通道](http://stackoverflow.com/a/34283635/1705598)。 (3认同)

Uve*_*tel 5

如果很少有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")
}
Run Code Online (Sandbox Code Playgroud)

尝试一下工作https://play.golang.org/p/sp8jk961TB

  • 如果您从多个go例程写入通道,则存在竞争条件。您需要使用锁来保护对通道的访问或使用原子指针。 (2认同)