使用Go检查通道是否具有可读取值

时间:2010-08-03 16:17:06

标签: go channel

如何检查频道是否有值供我阅读?

我不想在阅读频道时阻止。我想看看它是否有价值。如果它有一个,我会读它。如果它还没有(还),我会做其他的事情,稍后再回来查看。

谢谢!

6 个答案:

答案 0 :(得分:76)

我知道从通道读取的唯一非阻塞操作是在select block内有默认情况:

    select {
    case x, ok := <-ch:
        if ok {
            fmt.Printf("Value %d was read.\n", x)
        } else {
            fmt.Println("Channel closed!")
        }
    default:
        fmt.Println("No value ready, moving on.")
    }

try the non-blocking here

请注意以前的答案:接收运算符本身 现在是阻止操作,从Go 1.0.3开始。 spec已被修改。请try the blocking here(死锁)

答案 1 :(得分:7)

如果你经常这样做,那么它可能不是一个很棒的设计,如果没有任何东西可以从频道中读取,你可能最好再产生另一个goroutine去做你计划做的任何工作。 Go的通道的同步/阻塞性质使代码更容易阅读和推理,而调度程序和廉价的goroutine意味着异步调用是不必要的,因为等待goroutines占用非常少的资源。

答案 2 :(得分:7)

您没有,至少不适用于同步(无缓冲)频道。在没有要求从频道中获取值的情况下,无法判断值是否在等待。

对于缓冲通道,从技术上讲,您可以使用len函数来执行您描述的操作,但实际上,您确实不应该这样做。你的技术无效。

原因是它代表了竞争条件。给定通道ch,你的goroutine可能会看到len(ch)&gt; 0并得出结论,有一个值等待。但是,它无法得出结论,它可以在不阻塞的情况下从通道读取 - 另一个goroutine可能会在您检查len和接收操作运行的时间之间清空通道。

出于您所描述的目的,使用select作为Ripounet显示的默认案例。

答案 3 :(得分:6)

警告:这不再准确,请参阅下面的答案。

来自文档:

  

如果在一个中使用了接收表达式   分配或初始化   形式

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
     

接收操作变为   无阻塞。如果操作可以   继续,布尔变量ok将   设置为true并存储的值   X;否则ok设置为false和x   被设置为其类型的零值   

答案 4 :(得分:4)

不幸的是,以前的答案是不正确的。 spec明确表示您可以使用len()函数以这种方式使用通道,但前提是您指定了通道容量 - 通道时的​​缓冲区长度。如果在制作时省略了通道容量 - 通道操作总是阻塞。

答案 5 :(得分:-2)

在大多数情况下,依赖这些信息是一个非常糟糕的设计选择。甚至没有说它在实施中是如何肮脏的。

因此,不执行以下步骤来检测通道是否已准备好在运行时读取:

  • 定义 hchan waitq sudog 结构,如此处所定义 - https://golang.org/src/runtime/chan.go
  • 使用“unsafe”包将频道转换为指向 hchan struct
  • 的指针
  • 阅读此结构的 sendq 字段以获取侦听器
  • 首先阅读 sudog 并从那里读取msg字段。
  • 使用“reflect”和“unsafe”
  • 将msg转换为适当的频道类型