繁体   English   中英

同时选择一个发送和接收频道

[英]Select on a go send and receive channel at the same time

假设我有一个缓冲的发送和无缓冲接收通道:

s := make(chan<- int, 5)
r := make(<-chan int)

是否有可能同时select它们,以便在有任何内容可以读取时选择r ,如果它没有满,则会选择s 相当于此的东西,但不使用100%CPU:

for {
    if len(s) < cap(s) {
        // Send something
    }
    if len(r) > 0 {
        // Receive something
    }
}

请注意,我想决定在发送时发送的内容,而不是更早。

编辑

这个问题基本上等同于“我可以阻止直到某个频道准备发送, 而不发送任何内容吗?”

您可以使用select执行此操作,但由于要发送的值仅评估一次,如果两个通道都未就绪,则要发送的值将在发送时变得过时。

因此,添加一个default情况,如果没有任何通道准备就会执行,你只需要“睡眠”一点,然后再试一次(计算/获取更新后的新值)。 通过休眠,您将不会消耗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!
}

这是一个简单的选择:

select {
case s <- n:
    // Successful send.
case n := <- r:
    // Successful receive. Do something with n.
}

我可以阻止直到某个频道准备发送,而不发送任何内容吗?

不是原始的go频道。 您可能可以设法使用我的频道库中的SharedBuffer类型将某些东西拉到一起,但即使这样也很复杂,它在封面下使用了大量的反射。

https://godoc.org/github.com/eapache/channels#SharedBuffer

您可以发送一个可以计算值的对象,而不是直接发送值。 然后,您可以检测对象何时发送,然后进行计算。 您可以使用sync.Once确保计算完成一次,并对结果进行门控访问。 这可以避免使用Sleeps。

像这样: https//play.golang.org/p/oL2HA2jl91

暂无
暂无

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

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