在Golang中,如果频道channel
已关闭,我仍然可以使用以下语法从中读取内容,我可以测试ok
以查看它是否已关闭。
value, ok := <- channel
if !ok {
// channel was closed and drained
}
但是,如果我不知道某个频道是否已关闭并盲目写入,我可能会收到错误消息。我想知道是否有任何方法可以测试通道,只有当它没有关闭时才写入它。我问这个问题是因为有时我不知道goroutine中是否关闭了一个频道。
答案 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")
}
答案 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)
}
}
}