【发布时间】:2018-02-22 07:55:57
【问题描述】:
我有以下代码:
func sendRegularHeartbeats(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case <-time.After(1 * time.Second):
sendHeartbeat()
}
}
}
这个函数在一个专门的 go-routine 中执行并且每秒发送一个心跳消息。当上下文被取消时,整个过程应该立即停止。
现在考虑以下场景:
ctx, cancel := context.WithCancel(context.Background())
cancel()
go sendRegularHeartbeats(ctx)
这会以封闭的上下文启动心跳例程。在这种情况下,我不希望传输任何心跳。所以应该立即输入select中的第一个case块。
但是,似乎无法保证评估 case 块的顺序,并且代码有时会发送心跳消息,即使上下文已经取消。
实现这种行为的正确方法是什么?
我可以在第二个 case 中添加一个“isContextclosed”检查,但这看起来更像是一个丑陋的解决方法。
【问题讨论】:
-
虽然标题和stackoverflow.com/questions/11117382/…很相似,但这不是重复的。另一个问题的解决方案处理的是消费者/生产者问题,而不是上下文。
-
请参阅本文中的第 2 点。 tapirgames.com/blog/golang-concurrent-select-implementation ,您所经历的似乎是正常的
select行为。如果您想要更多控制权,您可能必须在没有上下文的情况下重新实现并继续使用consumer/producer解决方案 -
问题不一样,但答案是:先在ctx.Done上选择,如果没有取消(也选择),默认情况下发送心跳。环形。简单的。您不能强制选择优先级。不要再看下去了,这是可以撤消的。你必须嵌套选择。
-
@Volker 好点,发送到默认值应该可以解决问题
-
@Volker 您可以通过代码示例将此作为答案发布吗?我真的不明白这应该如何工作。如果上下文在 1 秒超时期间关闭,我也想中止(超时是可配置的,可以是一分钟或更长时间)
标签: go