繁体   English   中英

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

[英]Checking if a channel has a ready-to-read value, using Go

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

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

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

    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.")
    }

在这里尝试非阻止

备注以前的答案:接收运营商本身现在一个阻塞操作,如围棋1.0.3。 规范已被修改。 在这里尝试阻止 (死锁)

你没有,至少不是同步(无缓冲)通道。 如果没有要求从通道中获取值,则无法判断值是否在等待。

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

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

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

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

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

来自文档:

如果在表单的赋值或初始化中使用了接收表达式

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

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

不幸的是,以前的答案是不正确的。 规范清楚地表明,您可以使用len()函数以这种方式使用通道,但前提是您指定了通道容量 - 通道时的​​缓冲区长度。 如果在制作时省略了通道容量 - 通道操作始终处于阻塞状态。

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

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

  • 定义这里定义的hchan waitq sudog结构 - https://golang.org/src/runtime/chan.go
  • 使用“unsafe”包将通道转换为指向hchan结构的指针
  • 读取此结构的sendq字段以获取侦听器
  • 读取第一个 sudog并从那里读取msg字段。
  • 使用“反射”和“不安全”将msg转换为适当的通道类型

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM