当前位置: 首页 > 面试题库 >

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

柳坚白
2023-03-14
问题内容

我有以下代码:

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)将仅
在1秒后 准备就绪,因此一开始将不会被选择。但是,要在可能准备好多个案例时显式处理优先级,请继续阅读。

与语句的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上尝试一下。



 类似资料:
  • 我试图限制用户使用我的桶策略访问我的桶。我有一组用户,他们都有一个S3FullAccess策略。我不能改变IAM中的任何东西。我只能使用我的遗愿保单。所以我想使用桶策略控制用户的访问。我把用户分成3类。 管理员访问我的桶(所有访问我的桶) 访问我的桶的权限有限的用户(如get-buk-策略,get-buk-位置) 无法访问我的桶。(无法访问我的桶) 下面的策略是我尝试过的,但不起作用。 我尝试了上

  • 问题内容: 我希望在两个频道上进行go例程侦听,两个频道都排空时将其阻塞。但是,如果两个通道都包含数据,我希望先清空一个通道,再处理另一个通道。 在下面的工作示例中,我希望在处理所有内容之前先将其清空。我使用的-statement没有任何优先顺序。我如何解决这个问题,使所有10个超值都在出口之前得到处理? 问题答案: 第一次选择的默认情况使其变为非阻塞。该选择将耗尽输出通道,而无需查看出口通道,否

  • 一点背景:我是一个AEM项目的FE开发人员。该项目是一个SPA AEM作为云服务。我从命令行运行作者实例。 我的电脑规格是: CPU: Intel(R)Core(TM)i5-7400 CPU@3.00GHz 3.00 GHz RAM: 24.0 GB SSD: 476 GB 操作系统:Windows 10 Pro 对于我们正在使用的AEM项目 Javasdk 11 Maven 3.6.3 我已经设

  • 问题内容: 我目前正在使用Play!1.2.2及其新的Netty客户端框架。 尽管可以使HTTP和HTTPS异步提供服务,但我没有找到一种简单的方法来强制执行SSL。有没有与Play合作的人!有直接执行SSL的方法吗?不知道我是否需要创建重定向,或者是否可以在文件中快速解决此问题。 问题答案: 有两种方法可以强制实施SSL。 首先,您可以将所有操作设置为使用该方法,例如 另一种可能也是最好的方法是

  • 问题内容: 我很难理解一些代码,这些代码显示了一个示例,该示例如何将Java中的double转换为byte [],反之亦然。 这是用于将双精度型转换为byte []的代码: 这是用于将byte []转换为double的代码: 好的,这是我不太了解的部分。 似乎强制转换发生在实际的按位运算之前,因为作者说 该表达式将把字节放在长[…]处,然后应用mask删除java施加的符号 在实际转换之前,如何将

  • 问题内容: 我在Hibernate尝试了简单的程序,并发现了一堆异常。 我不知道到底是什么问题。 我有三个课程-书籍,阅读器和使用。最后一个是将前两个绑定为一对多。 这是我的: 这是异常消息: 的摘要: DB上的所有表均已创建,但为空。一切都还好。有什么建议么? 如何解决这个麻烦? 问题答案: 在MySQL中, USING 是保留字。 因此,只需使用实体上的注释来重命名表即可。就像是 我假设您有一