英文:
Go buffered channel falls through select
问题
我有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 message to either RabbitMQ or SQS")
}
} else {
sqsQ <- params
}
}
我期望消息总是被发送到 rabbitQ,除非缓冲区已满,但我发现有大约一半的时间调用会继续执行,并将消息发送到 sqsQ。这不是我想要的 - 我只想在 rabbitQ 满时才发送到 sqsQ。
我该如何强制执行这一点?
英文:
I have 2 buffered channels servicing inbound requests:
rabbitQ = make(chan map[string]interface{}, 1000)
sqsQ = make (chan map[string]interface{}, 1000)
My dispatcher function looks like this:
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
}
}
I would expect that messages would always be sent to rabbitQ unless the buffer was at capacity but I'm finding that the call is falling through and sending messages to sqsQ about half the time. This is not what I want - I only want to send to sqsQ if rabbitQ is full.
How can I enforce this?
答案1
得分: 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")
}
}
}
英文:
Per Voker's comment, this is what I came up with:
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
得分: 0
对于简洁的答案(从你的回答和线程评论中看起来你已经有了答案),你的选择将随机选择。根据文档:
> 如果一个或多个通信可以进行,将通过均匀伪随机选择选择一个可以进行的通信。否则,如果有默认情况,将选择该情况。如果没有默认情况,则“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("无法将消息分派到RabbitMQ或SQS")
}
} else {
if len(sqsQ) < MaxChan {
sentToRabbitMQ++
} else if len(rabbitQ) < MaxChan {
sentToSQS++
} else {
log.Error("无法将消息分派到RabbitMQ或SQS")
}
}
}
支持文档:
https://golang.org/ref/spec#Select_statements
英文:
For a concise answer (it looks like you already have it from your answer + the thread comment), your select will choose at random. Per the docs:
> If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
In addition, I figured I would provide you with an answer that doesn't use selects at all. Using len, you can determine how many values are queued up in a channel. Sure it's no different than what you're doing now, but I figured I would offer something different:
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")
}
}
}
Supporting docs:
https://golang.org/ref/spec#Select_statements
答案3
得分: 0
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 message to either RabbitMQ or SQS")
}
}
} else {
sqsQ <- params
}
}
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("无法将消息分发到RabbitMQ或SQS")
}
}
} else {
sqsQ <- params
}
}
英文:
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
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论