假设我有一个缓冲的发送和无缓冲接收通道:
s := make(chan<- int, 5)
r := make(<-chan int)
是否可以对它们select
进行操作,以便在有任何内容需要阅读的情况下选择r
,如果未填写s
,则会选择for {
if len(s) < cap(s) {
// Send something
}
if len(r) > 0 {
// Receive something
}
}
?相当于此的东西,但没有使用100%CPU:
{{1}}
请注意,我想决定在发送时发送的内容,而不是更早。
这个问题基本上等同于&#34;我可以阻止直到一个频道准备发送,没有发送任何内容吗?&#34;
答案 0 :(得分:1)
您可以使用select
执行此操作,但由于要发送的值仅评估一次,如果两个通道都未就绪,则要发送的值在发送时将过时。
所以添加一个default
案例,如果没有任何一个频道准备就绪,将会执行这个案例,你只需要睡觉&#34;稍微再试一次(计算/获取更新的新值)。通过休眠,您不会消耗CPU资源:
s := make(chan<- int, 5)
r := make(<-chan int)
for {
v := valueToSend() // Evaluated each time we try to send
select {
case s <- v:
fmt.Println("Sent value:", v)
case vr := <-r:
fmt.Println("Received:", vr)
default: // If none are ready currently, we end up here
time.Sleep(time.Millisecond * 1)
}
}
注意检查频道的长度或容量,然后发送/接收不被视为一个好的解决方案,因为在您检查之间频道可能没有准备好它的长度/上限,你尝试发送/接收,如下图所示:
if len(r) > 0 {
// r is ready to receive
// Optional other code here,
// meanwhile another goroutine might receive the value from r!
r <- // If other goroutine received from r, this will block!
}
答案 1 :(得分:0)
这是一个简单的选择:
select {
case s <- n:
// Successful send.
case n := <- r:
// Successful receive. Do something with n.
}
答案 2 :(得分:0)
我可以阻止直到某个频道准备发送,而不发送任何内容吗?
不是原始的go频道。你可能会设法使用我的频道库中的SharedBuffer
类型将某些内容拉到一起,但即使这样也很复杂,它会在封面下使用大量的反射。
答案 3 :(得分:0)
您可以发送一个可以计算值的对象,而不是直接发送值。然后,您可以检测对象何时发送,然后进行计算。您可以使用sync.Once确保计算完成一次,并对结果进行门控访问。这可以避免使用Sleeps。