如何检查 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)
),但是如果你以后尝试这样做,并不能保证仍然可以接收到这个值。
如果您确实需要此功能,请使用计数器来代替原子读写。可以在不递减计数器的情况下读取计数器的值。
如果您确实需要通道,使用 select
和 default
案例就足够了:您可以进行非阻塞发送和接收,如果发送或接收会阻塞,default
案例将是无阻塞地执行。
【讨论】:
【参考方案2】:频道不会阻塞; communications(send 或 receive)可能会阻止它们。
在不实际尝试相关通信的情况下检查通道通信是否会阻塞在 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 通道是不是真的在等待数据?的主要内容,如果未能解决你的问题,请参考以下文章