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

Tim*_*mmm 5 select channel go

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

s := make(chan<- int, 5)
r := make(<-chan int)
Run Code Online (Sandbox Code Playgroud)

是否可以select对它们进行操作,以便r在有任何内容s可供选择的情况下进行选择,如果未完整则会被选中?相当于此的东西,但不使用100%CPU:

for {
    if len(s) < cap(s) {
        // Send something
    }
    if len(r) > 0 {
        // Receive something
    }
}
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

icz*_*cza 5

您可以这样做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)
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,检查通道的长度或容量然后发送/接收并不被认为是一个好的解决方案,因为在检查其长度/容量和尝试发送/接收之间通道可能未准备好,如下所示:

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!
}
Run Code Online (Sandbox Code Playgroud)


Ain*_*r-G 1

这是一个简单的选择:

select {
case s <- n:
    // Successful send.
case n := <- r:
    // Successful receive. Do something with n.
}
Run Code Online (Sandbox Code Playgroud)

  • @Timmmm它在[规范](http://golang.org/ref/spec#Select_statements)中。*在输入“select”语句时,发送语句的右侧表达式仅计算一次。* (3认同)