强制执行go select语句的优先级

func sendRegularHeartbeats(ctx context.Context) {

for {

select {

case <-ctx.Done():

return

case <-time.After(1 * time.Second):

sendHeartbeat()

}

}

}

此功能在专用的go例程中执行,并每秒发送一次心跳消息。取消上下文后,整个过程应立即停止。

ctx, cancel := context.WithCancel(context.Background())

cancel()

go sendRegularHeartbeats(ctx)

这将在关闭的上下文中启动心跳例程。在这种情况下,我不希望传输任何心跳。因此,case应该立即输入选择中的第一个块。

但是,似乎case无法保证对块进行评估的顺序,并且即使上下文已取消,该代码有时也会发送心跳消息。

我可以在第二个中添加“ isContextclosed”检查case,但这看起来更像是解决该问题的丑陋方法。

回答:

您的示例将按您的预期工作,就像sendRegularHeartbeats()调用时上下文已被取消一样,case

<-ctx.Done()通信将是唯一可以进行并因此被选择的通信。另一个case <-time.After(1 * time.Second)将仅

准备就绪,因此一开始将不会被选择。但是,要在可能准备好多个案例时显式处理优先级,请继续阅读。


与语句的case分支(评估顺序为列出的顺序)不同,语句的分支中没有优先级或任何保证的顺序。switchcaseselect

引用规格:选择语句:

如果可以进行一种或多种通信 可以进行

通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则“ select”语句将阻塞,直到可以进行至少一种通信为止。

如果可以进行更多通信,则随机选择一个。期。

如果要保持优先级,则必须自己(手动)执行此操作。您可以使用多个select语句(随后的语句,而不是嵌套的语句)来执行此操作,在 较早的

语句中列出优先级更高的语句select,并且还请确保添加一个default分支,以避免在语句尚未准备好进行时阻塞。您的示例需要2条select语句,第一个检查,<-ctx.Done()因为这是您想要更高优先级的语句。

我还建议在每次迭代中使用单个time.Ticker而不是调用time.After()time.After()也使用time.Ticker幕后花线,但它不会重用它,只是“扔掉”并在下一次调用时创建一个新的)。

这是一个示例实现:

func sendRegularHeartbeats(ctx context.Context) {

ticker := time.NewTicker(time.Second)

defer ticker.Stop()

for {

select {

case <-ctx.Done():

return

default:

}

select {

case <-ctx.Done():

return

case <-ticker.C:

sendHeartbeat()

}

}

}

如果sendRegularHeartbeats()调用时上下文已被取消,则不会发送任何心跳信号,因为您可以在Go

Playground上进行检查/验证。

如果您将cancel()通话延迟2.5秒,则将精确发送2个心跳:

ctx, cancel := context.WithCancel(context.Background())

go sendRegularHeartbeats(ctx)

time.Sleep(time.Millisecond * 2500)

cancel()

time.Sleep(time.Second * 2)

在Go Playground上尝试一下。

以上是 强制执行go select语句的优先级 的全部内容, 来源链接: utcz.com/qa/400067.html

回到顶部