【问题标题】:Go buffered channel falls through selectGo 缓冲通道通过 select
【发布时间】:2017-05-17 21:55:49
【问题描述】:

我有 2 个缓冲通道服务入站请求:

rabbitQ = make(chan map[string]interface{}, 1000)
sqsQ = make (chan map[string]interface{}, 1000)

我的调度程序函数如下所示:

func dispatchMessage(params map[string]interface{}) {

    if !shouldFailoverToSQS {
        select {
        case rabbitQ <- params:
            sentToRabbitMQ++
        case sqsQ <- params:
            sentToSQS++
        default:
            log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
        }
    } else {
        sqsQ <- params
    }

}

我希望消息总是被发送到rabbitQ,除非缓冲区已满,但我发现调用失败并且大约有一半时间将消息发送到sqsQ。这不是我想要的 - 如果 rabbitQ 已满,我只想发送到 sqsQ。

我该如何执行?

【问题讨论】:

  • Select 随机选择一个可运行的案例。如果你不想要这个随机选择,你不能有两个案例,而只有一个发送给 rabbitQ。如果这种情况无法运行,您点击默认情况并发送到 sqs(可能在嵌套选择中以允许失败日志记录)。

标签: go channels


【解决方案1】:

根据 Voker 的评论,这是我想出的:

func dispatchMessage(params map[string]interface{}) {

    //log.Debugf("Failover: %t, Len: %d", shouldFailoverToSQS, len(rabbitQ))

    if !shouldFailoverToSQS {
        select {
        case rabbitQ <- params:
            sentToRabbitMQ++
        default:
            select {
            case sqsQ <- params:
                sentToSQS++
            default:
                log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
            }
        }
    } else {
        select {
        case sqsQ <- params:
            sentToSQS++
        default:
            log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
        }
    }

}

【讨论】:

    【解决方案2】:

    对于简洁的答案(看起来您已经从答案 + 主题评论中获得了答案),您的选择将随机选择。根据文档:

    如果一个或多个通信可以继续,则通过统一的伪随机选择选择一个可以继续的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。

    此外,我想我会为您提供一个根本不使用选择的答案。使用 len,您可以确定有多少值在通道中排队。当然这和你现在所做的没什么不同,但我想我会提供一些不同的东西:

    const MaxChan = 1000
    func dispatchMessage(params map[string]interface{}) {
        if !shouldFailoverToSQS {
            if len(rabbitQ) < MaxChan {
                sentToRabbitMQ++
            } else if len(sqsQ) < MaxChan {
                sentToSQS++
            } else {
                log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
            }
        } else {
            if len(sqsQ) < MaxChan {
                sentToRabbitMQ++
            } else if len(rabbitQ) < MaxChan {
                sentToSQS++
            } else {
                log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
            }
        }
    }
    

    支持文档: https://golang.org/ref/spec#Select_statements

    【讨论】:

      【解决方案3】:
      func dispatchMessage(params map[string]interface{}) {
      
          if !shouldFailoverToSQS {
              select {
              case rabbitQ <- params:
                  sentToRabbitMQ++
              case <-time.After(time.Millisecond * 10.0): // rabbit is blocked and 10 milli sec passed.
                  select {
                  case sqsQ <- params:
                      sentToSQS++  
                  default:
                  log.Error("Failed to dispatch mesaage to either RabbitMQ or SQS")
                  }
              }
          } else {
              sqsQ <- params
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2019-01-07
        • 1970-01-01
        • 2017-09-06
        • 2018-10-02
        • 2021-12-25
        • 2013-12-17
        • 2018-04-15
        • 2012-10-17
        • 2014-01-30
        相关资源
        最近更新 更多