英文:
How to check whether a go channel is actually waiting for data?
问题
我只想在某个通道阻塞等待数据到来时才继续执行(阻塞通道是一个工作的Go协程的一部分,应该并行运行)。
像这样:
func foo(c chan bool) {
go start_blocking(c)
// 只有当通道c真正阻塞时才执行到这里!
}
func start_blocking(c chan bool) {
<-c
}
如何实现这个目标?
目的:
该通道在稍后某个时间等待数据到来,并且应该在主执行继续之前在后台准备好。
英文:
I want to only proceed with my execution when a certain channel blocks waiting for data to come (the blocking channel is part of a working go routine, supposed to run in parallel).
Like:
func foo(c chan bool) {
go start_blocking(c)
// only come here, when channel c actually blocks!
}
func start_blocking(c chan bool) {
<-c
}
How to achieve this?
Purpose:
The channel is waiting for data to come at some time later and it should be ready in the background, before the main execution continues.
答案1
得分: 5
你不能在不实际接收通道数据的情况下"窥视"通道。因此,如果你真的需要这个功能,通道不是一个好的工具。如果你有一个带缓冲区的通道,当然可以通过检查其缓冲区的长度(len(ch)
)来判断是否有值,但不能保证在之后尝试接收时仍然可以接收到该值。
如果你确实需要这个功能,可以使用原子读写的计数器代替。可以读取计数器的值而不减少它。
如果你确实需要一个通道,可以使用带有default
情况的select
语句:你可以进行非阻塞的发送和接收,如果发送或接收会阻塞,将执行default
情况而不会阻塞。
英文:
You can't "peek" a channel without actually receiving from it. So channels are not a good tool if you really need this functionality. If you have a buffered channel, you can of course check if there's a value in its buffer by checking its length (len(ch)
), but there's no guarantee the value can still be received if you attempt to do it afterwards.
If you do need this functionality, use a counter instead with atomic reads and writes. It is possible to read a counter's value without decrementing it.
And if you do need a channel, using a select
with default
case should suffice: you may do non-blocking send and receive, and if a send or receive would block, the default
case will be executed without blocking.
答案2
得分: 3
通道本身不会阻塞;在通道上进行的通信(发送或接收)可能会阻塞。
在Go语言中,检查通道通信是否会阻塞而不实际尝试通信并不是很常见,原因如下所述。然而,如果这确实是你想要的,你可以按照以下步骤进行操作。对于给定的(有缓冲的)通道ch
,你可以:
- 检查
len(ch) == cap(ch)
来确定发送是否会阻塞; - 检查
len(ch) == 0
来确定接收是否会阻塞。
然而,这两个检查很可能很快就会过时,因为在你进行检查后不久,另一个goroutine可能已经向通道发送或接收了数据;这是时间检查到使用的经典实例(TOCTOU)。
正如评论中指出的,这种方法的一个注意事项是它不适用于无缓冲的通道,对于无缓冲的通道,这两个条件总是评估为true
。
英文:
Channels don't block; it's communications (send or receive) on them that may block.
Checking whether a channel communication would block without actually attempting the communication in question is not very idiomatic in Go, for reasons discussed below. However, if that's really what you want, you could do the following. For a given (buffered!) channel ch
, you could
- check
len(ch) == cap(ch)
to determine whether a send would block; - check
len(ch) == 0
to determine whether a receive would block.
However, both checks are likely to become stale very quickly, because another goroutine may have sent to or received from the channel shortly after your check; a classic instance of time-of-check to time-of-use (TOCTOU).
And as pointed out in the comments, one caveat of this approach is that it doesn't work for unbuffered channels, for which the two conditions invariably evaluate to true
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论