事先注意:
您的示例将按您的预期工作,就像
sendRegularHeartbeats()调用时上下文已被取消一样,
case<-ctx.Done()通信将是唯一可以进行并因此被选择的通信。另一个
case <-time.After(1 * time.Second)将仅
在1秒后 准备就绪,因此一开始将不会被选择。但是,要在可能准备好多个案例时显式处理优先级,请继续阅读。
与语句的
case分支(评估顺序为列出的顺序)不同,语句的分支中没有优先级或任何保证的顺序。
switch
case
select
引用规格:选择语句:
如果可以进行一种或多种通信 ,则可以通过统一的伪随机选择来选择 可以进行 的单个
通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,则“ 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上尝试一下。



