【问题标题】:Reliable way to ensure a Go channel does not block确保 Go 通道不会阻塞的可靠方法
【发布时间】:2015-02-25 12:51:29
【问题描述】:

我正在寻找一种可靠的方法来确保 Go 中的空通道不会阻止我的执行。我必须以特定顺序(某种优先级)遍历多个渠道,一旦找到其中包含项目的渠道,请阅读其中一个。

目前我以类似的方式做一些事情:

if len(myChannel) > 0 {
    // Possible issue here: length could have changed to 0 making this blocking
    elm := <- myChannel
    return elm
}

理论上,这可能会导致等待时间过长,而不同的频道可能有一个准备好“服务”的项目。

关于如何改进的任何建议?我可以在频道中使用互斥锁,但感觉好像有更好的解决方案,虽然我不确定如何。

【问题讨论】:

  • 为什么不使用select 声明?
  • 如何以动态方式编写这样的语句(例如迭代通道数组)?
  • 一般来说,当多个 goroutine 写入这些通道时,不可能做你想做的事。在检查通道是否有剩余空间和发送到该通道的操作之间,其他人可能在通道中放入了一些东西,导致它阻塞。
  • @FUZxxl 所以这意味着每个通道的互斥锁将是唯一真正的解决方案?
  • @RobinUS2 或所有通道的一个互斥锁...正如我所说,这取决于您的用例。如果只有一个 Go 例程写入通道,则不需要。

标签: go channel lock-free


【解决方案1】:

有一个reflect.Select 函数可以做你想做的事:

package main

import (
    "fmt"
    "reflect"
    "time"
)

func main() {
    a, b, c := make(chan int), make(chan int), make(chan int)
    go func() {
        time.Sleep(2 * time.Second)
        a <- 1
    }()
    go func() {
        time.Sleep(time.Second)
        b <- 2
    }()
    go func() {
        time.Sleep(3 * time.Second)
        c <- 3
    }()
    for i := 0; i < 3; i++ {
        chosen, recv, ok := reflect.Select([]reflect.SelectCase{
            reflect.SelectCase{
                Dir:  reflect.SelectRecv,
                Chan: reflect.ValueOf(a),
            },
            reflect.SelectCase{
                Dir:  reflect.SelectRecv,
                Chan: reflect.ValueOf(b),
            },
            reflect.SelectCase{
                Dir:  reflect.SelectRecv,
                Chan: reflect.ValueOf(c),
            },
        })
        if ok {
            fmt.Printf("Got value %d from %d\n", recv.Interface().(int), chosen)
        }
    }
}

play.golang.org

【讨论】:

    【解决方案2】:

    我不确定这是否真的回答了“是否有可靠的方法来确保 Go 通道不会阻塞”的问题。在 OP 的用例中,如果 recv 阻塞 / 只要集合中没有其他通道不会阻塞 / 就可以了,这就是公认的解决方案所实现的。这与“确保 recv 不会阻塞”不同,我认为没有办法绕过 OP 指出的竞争条件的基本限制。

    【讨论】:

    • 您不知道select 带有default: 的情况吗?这允许非阻塞通道操作。 (例如,在没有任何种族的情况下阅读或不阅读)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-21
    • 1970-01-01
    • 2015-12-08
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    相关资源
    最近更新 更多