Go 如何测试通道是否已关闭,并且仅在未关闭时发送给它
在Go中,如果一个通道关闭,我仍然可以使用以下语法读取它,并且我可以测试ok以查看它是否关闭Go 如何测试通道是否已关闭,并且仅在未关闭时发送给它,go,channel,Go,Channel,在Go中,如果一个通道关闭,我仍然可以使用以下语法读取它,并且我可以测试ok以查看它是否关闭 value, ok := <- channel if !ok { // channel was closed and drained } 但是,如果我不知道某个通道是否已关闭,并且盲目地对其进行写入,则可能会出错。我想知道是否有任何方法可以测试通道,并且只在通道未关闭时写入。我问这个问题是因为有时我不知道goroutine中的频道是否关闭。你不能。这里的经验法则是只有编剧才应该关闭频道,
value, ok := <- channel
if !ok {
// channel was closed and drained
}
但是,如果我不知道某个通道是否已关闭,并且盲目地对其进行写入,则可能会出错。我想知道是否有任何方法可以测试通道,并且只在通道未关闭时写入。我问这个问题是因为有时我不知道goroutine中的频道是否关闭。你不能。这里的经验法则是只有编剧才应该关闭频道,这样你就知道你不应该再给那个频道写信了 一些简单的代码如下所示:
for i := 0; i < 100; i++ {
value := calculateSomeValue()
channel <- value
}
close(channel) //indicate that we will no more send values
如果很少有goroutin写入通道,您也可以将其置零,而不是关闭,并使用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")
}
试着让它工作吧你做不到。您可以将消息发送到通道的工作与另一个从通道读取的go例程分开 当读卡器完成时,您应该添加一个donechannel来发出信号 例如
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)
}
}
}
如果您不知道某个频道是否关闭,并且盲目地对其进行写入,那么您的程序设计就很糟糕。重新设计它,这样在它关闭后就没有办法写进去了。是的@ain,我完全同意你的观点!我只是想知道,从技术上讲,是否有办法做到这一点。相关/可能重复:这是否回答了你的问题?如果多个goroutine写入同一个通道怎么办?如果一个goroutine完成了它的工作,它不能简单地关闭通道。其他goroutine可能仍然需要写入通道。@OgrishMan:那么当所有goroutine完成后,您就有一个外部观察者关闭通道,或者根本不关闭它。@OgrishMan在回答中看到了使用sync.WaitGroup解决此问题的方法:。默认值是否意味着当前没有数据,或者通道已关闭以供进一步阅读?下面是一些代码来回答您的问题:`closech select{case value,ok:=它将变成默认值,就像switch语句一样。我添加了以下代码来测试通道是否关闭。如果通道关闭,ok var将为false,值将为0,这是int的默认nil值。下面是一些代码来回答您的问题:`closech select{case value,ok:=如果从多个go例程写入通道,则会出现竞争条件。您需要使用锁或原子指针保护对通道的访问。即使使用select,尝试写入闭合通道时也会出现恐慌,请参阅此代码