【问题标题】:Conditional Timeout条件超时
【发布时间】:2020-08-08 00:28:33
【问题描述】:

我有一些代码,有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 设为可选,但不知道如何处理它。如果我用if 语句围绕waitTimer 的构造,那么它不会像waitTimer 那样为select 语句定义......我怎样才能使WaitTimeout 有条件?

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

【问题讨论】:

    标签: go timer channel


    【解决方案1】:

    您可以在if 语句之外声明等待计时器及其通道,并且仅在需要等待计时器时才初始化它们。如果没有,通道可能会保持其零值——即nil——因为从nil 通道接收永远阻塞,所以这个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,不要忘记耗尽通道):

    // stop wait timer if exists
    if waitTimer != nil && !waitTimer.Stop() {
        <-waitTimerC
    }
    

    Go Playground 上试试。

    【讨论】:

    • 能否解释一下为什么你做了waitTimer *time.Timer 而不是waitTimer time.Timer ? Go 新手
    • 因为time.NewTimer()返回一个*time.Timer类型的值,一个指针,而不是time.Timer
    • OK - 所以类型匹配。谢谢
    猜你喜欢
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 2022-01-17
    • 2023-04-03
    • 2019-04-27
    • 2019-11-22
    • 2016-09-12
    相关资源
    最近更新 更多