go - 条件超时

标签 go timer channel

我有一些代码,有 3 个计时器,

  • GracefulExecutionTimeout - 总运行时间
  • WaitTimeout - 初始等待第一条消息的时间
  • IdleTimeout - 等待后续消息的时间

  • 如果达到任何计时器,应用程序应该干净地退出。我让它在下面工作
    msgs := make(chan string)
    
    go func() {
        time.Sleep(time.Second)
        msgs <- "test"
    }()
    // graceful max execution time
    gracefulMaxTimeout := time.Second * time.Duration(10)
    gracefulMaxTimer := time.NewTimer(gracefulMaxTimeout)
    
    // idleTimeout
    idleTimeout := time.Second * time.Duration(5)
    idleTimer := time.NewTimer(idleTimeout)
    
    // waitTimeout
    waitTimeout := time.Second * time.Duration(2)
    waitTimer := time.NewTimer(waitTimeout)
    for {
        select {
        case <-gracefulMaxTimer.C:
            fmt.Println("GracefulMaxExecutionTimeout Reached")
    
            // graceful exit
            os.Exit(0)
        case <-idleTimer.C:
            fmt.Println("IdleTimeout Reached")
    
            // graceful exit
            os.Exit(0)
        case <-waitTimer.C:
            fmt.Println("WaitTimeout Reached")
            // graceful exit
            os.Exit(0)
        case msg := <-msgs:
            // stop wait timer
            waitTimer.Stop()
            fmt.Println(msg)
    
            // Reset idle timer
            if !idleTimer.Stop() {
                <-idleTimer.C
            }
            fmt.Println("IdleIimeout Reset")
            idleTimer.Reset(idleTimeout)
        }
    }
    

    Go Playground

    我想将 WaitTimeout 设为可选,但不知道如何处理它。如果我围绕 waitTimer 的构造与 if那么它就不能作为 waitTimer没有为 select 定义声明...我怎样才能使 WaitTimeout 有条件?

    我可以 .Stop()创建后的计时器,但这似乎有点脏...

    最佳答案

    您可以在 if 之外声明等待计时器及其 channel 。语句,并且仅在需要等待计时器时才初始化它们。如果不是, channel 可能保持其零值——nil ——因为从 nil 接收 channel 永远阻塞,所以这个 case永远不会准备好(详情见 How does a non initialized channel behave? )。

    useWaitTimer := true
    
    var (
        waitTimer  *time.Timer
        waitTimerC <-chan time.Time
    )
    if useWaitTimer {
        waitTimeout := time.Millisecond * time.Duration(500)
        waitTimer = time.NewTimer(waitTimeout)
        waitTimerC = waitTimer.C
    }
    
    // ...
    
    for {
        select {
        // ...
    
        case <-waitTimerC:
            fmt.Println("WaitTimeout Reached")
            // graceful exit
            os.Exit(0)
    
        // ...
        }
    }
    

    然后当然你只能重置等待计时器,如果它存在,这也必须检查(如果它返回 false,不要忘记耗尽 channel ):
    // stop wait timer if exists
    if waitTimer != nil && !waitTimer.Stop() {
        <-waitTimerC
    }
    

    Go Playground 上试用.

    关于go - 条件超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61795339/

    相关文章:

    当我的主循环等待 channel 滴答和传递事件时,OpenGl 似乎卡住了

    android - 需要我的 android 应用程序的设计建议

    linux - 如何在Linux中提高1ms定时器的实时性能?

    interface - 在 go 中输入不可知的 channel

    concurrency - 关闭 channel

    go - 如何实现子路由

    Go 函数创建泛型类型的新指针或新值

    go - VSCode 是如何发现这个 Go linting 问题的?我该如何忽略它?

    数学游戏 Tkinter 中的 Python 计时器

    testing - 如何测试在 spring-integration 中使用 channel 的热文件夹?