Go 如何测试通道是否已关闭,并且仅在未关闭时发送给它

Go 如何测试通道是否已关闭,并且仅在未关闭时发送给它,go,channel,Go,Channel,在Go中,如果一个通道关闭,我仍然可以使用以下语法读取它,并且我可以测试ok以查看它是否关闭 value, ok := <- channel if !ok { // channel was closed and drained } 但是,如果我不知道某个通道是否已关闭,并且盲目地对其进行写入,则可能会出错。我想知道是否有任何方法可以测试通道,并且只在通道未关闭时写入。我问这个问题是因为有时我不知道goroutine中的频道是否关闭。你不能。这里的经验法则是只有编剧才应该关闭频道,

在Go中,如果一个通道关闭,我仍然可以使用以下语法读取它,并且我可以测试ok以查看它是否关闭

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,尝试写入闭合通道时也会出现恐慌,请参阅此代码