如何检查 go 通道是不是真的在等待数据?

Posted

技术标签:

【中文标题】如何检查 go 通道是不是真的在等待数据?【英文标题】:How to check whether a go channel is actually waiting for data?如何检查 go 通道是否真的在等待数据? 【发布时间】:2021-10-29 00:19:59 【问题描述】:

我只想在某个通道阻塞等待数据到来时继续我的执行(阻塞通道是工作 go 例程的一部分,应该并行运行)。

喜欢:

func foo(c chan bool) 

    go start_blocking(c)
    
    // only come here, when channel c actually blocks!


func start_blocking(c chan bool) 

    <-c

如何做到这一点?

目的:

通道在稍后等待数据到来,它应该在后台准备好,主执行继续之前。

【问题讨论】:

您可以使用select 来执行通信操作,或者如果当前会阻塞,请执行其他操作。这还不够吗? 但我只是想测试通道是否阻塞,我不想消耗任何东西。如果可以的话,try-receive 选择模式也会接收/消费,对吧? 您的问题有一个问题:频道不会阻塞;它的通信(发送或接收)在那个块上。 @jub0bs 但你明白了吗?然后可能将其改写为:检查 go 例程何时实际等待 rcv 数据的通道。更好? “如何检查通道上的操作是否会阻塞?”作为标题? 【参考方案1】:

您无法“窥视”频道而不实际接收频道。因此,如果您确实需要此功能,则通道不是一个好工具。如果你有一个缓冲通道,你当然可以通过检查它的长度来检查它的缓冲区中是否有一个值(len(ch)),但是如果你以后尝试这样做,并不能保证仍然可以接收到这个值。

如果您确实需要此功能,请使用计数器来代替原子读写。可以在不递减计数器的情况下读取计数器的值。

如果您确实需要通道,使用 selectdefault 案例就足够了:您可以进行非阻塞发送和接收,如果发送或接收会阻塞,default 案例将是无阻塞地执行。

【讨论】:

【参考方案2】:

频道不会阻塞; communicationssendreceive)可能会阻止它们。

在不实际尝试相关通信的情况下检查通道通信是否会阻塞在 Go 中并不是很习惯,原因如下所述。但是,如果这确实是您想要的,您可以执行以下操作。对于给定的(缓冲的!)频道ch,您可以

检查len(ch) == cap(ch) 以确定发送是否会阻塞; 检查len(ch) == 0 以确定接收是否会阻塞。

但是,这两个检查很可能很快就会变得陈旧,因为在您检查后不久,另一个 goroutine 可能已经发送到通道或从通道接收; time-of-check to time-of-use (TOCTOU) 的经典实例。

正如 cmets 中所指出的,这种方法的一个警告是它不适用于无缓冲通道,这两个条件总是评估为 true

【讨论】:

只适用于缓冲通道,不是吗? @MrFuppes 是的,检查len(ch) == cap(ch) 不适用于无缓冲通道,因为无缓冲通道的 len 和 cap 始终为 0,无论接收或发送是否会阻塞。 确实如此:这不适用于无缓冲通道。 “对于给定(无缓冲!)通道”应该是“对于给定(缓冲!)通道” @Adrian 谢谢!固定。

以上是关于如何检查 go 通道是不是真的在等待数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何在循环中创建频道?

Go:缓冲通道总和更快?

如何使用通道在 go 例程之间传递字节片

如何使用 websocket 检查消息是不是真的在 Netty 中传递?

如何关闭多个 goroutine 正在发送的通道?

如何检查加载到 FMX.TBitmap 的 PNG 图像是不是具有 alpha 通道?