在Golang中以最小间隔调用具有可变执行时间的函数的最佳方法?

时间:2019-02-05 01:41:22

标签: go timer

我想在Go中给定的时间间隔内执行功能,该时间间隔是从一次调用的开始到下一次调用的开始进行衡量的。函数本身的执行时间会有所不同。

如果该函数的运行时间超过该间隔,我想立即再次运行它。但是,如果/当它最终在不到一个完整的间隔内恢复完成时,我希望它立即恢复等待直到下一个间隔边界。

在上下文中,这是一个速率限制器–调用的函数可以轻松旋转CPU,但不会产生附加值,因为它与无法快速反应的人进行交互。

为清晰起见的示例(示例中为interval == 20ms

runtime:  15ms
wait:      5ms
runtime:  25ms
wait:      0ms
runtime:  25ms
wait:      0ms
runtime:  15ms
wait:      5ms <-- this is the important bit

如果我使用time.Ticker,我相信会在Ticker.C通道(如果已缓冲)中排队其他“滴答声”,从而使其在恢复时立即进行一连串的调用,否则,股票代码的编写者将阻止对该通道的写入,并在恢复后的第一次调用中最终导致恢复时间过长。

现在我正在做一些数学运算,该运算法则是有效的,但是感觉好像很不习惯:

minDurationBetweenRuns := time.Millisecond * 100
for {
    lastRunTime := time.Now()

    DO_STUFF_HERE()

    durationSinceLastRun := time.Now().Sub(lastRunTime)
    if durationSinceLastRun < minDurationBetweenRuns {
        sleepTime := minDurationBetweenRuns - durationSinceLastRun
        if sleepTime > minDurationBetweenRuns {
            sleepTime = minDurationBetweenRuns
        }
        time.Sleep(sleepTime)
    }
}

1 个答案:

答案 0 :(得分:4)

在撰写问题时,我想起了Golang的源代码非常容易阅读...并且认为我应该在偷看之前先看一下。我对发现的结果感到满意:)

the source中对time.Ticker的评论说,如果滴答阅读器落在后面,它将开始滴答滴答声,而不是阻塞写入通道(只有1个缓冲区)。这样的作用是在我们错过一个或多个刻度后立即使事情“回到正轨”。

证明示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.NewTicker(time.Millisecond * 50)
    for i := 0; i < 10; i++ {
        fmt.Printf("New invocation starting at %dms\n", time.Now().Round(time.Millisecond).Nanosecond()/int(time.Millisecond))
        if i%3 == 0 {
            fmt.Println("Executing for 25ms")
            time.Sleep(time.Millisecond * 25)
        } else {
            fmt.Println("Executing for 75ms")
            time.Sleep(time.Millisecond * 75)
        }
        fmt.Println("Waiting for ticker...")
        <-t.C
    }
    t.Stop()
}

输出:

New invocation starting at 0ms
Executing for 25ms
Waiting for ticker...
New invocation starting at 50ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 125ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 200ms
Executing for 25ms
Waiting for ticker...
New invocation starting at 250ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 325ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 400ms
Executing for 25ms
Waiting for ticker...
New invocation starting at 450ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 525ms
Executing for 75ms
Waiting for ticker...
New invocation starting at 600ms
Executing for 25ms
Waiting for ticker...