【问题标题】:Performance of time.Ticker时间的表现.Ticker
【发布时间】:2021-07-02 06:10:46
【问题描述】:

无法找出我们在下面的 for 循环中的哪个位置花费了超过 10 微秒,从而丢失了大量的滴答声?

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    RunTicker(time.Millisecond, 10 * time.Second) // Scenario 1
    RunTicker(10 * time.Microsecond, 10 * time.Second) // Scenario 2
}

func RunTicker(tickerInterval, tickerDuration time.Duration) {
    var counter int

    ctx, can := context.WithTimeout(context.Background(), tickerDuration)
    defer can()

    ticker := time.NewTicker(tickerInterval)

exitfor:
    for {
        select {
        case <-ticker.C:
            counter++
        case <- ctx.Done():
            ticker.Stop()
            break exitfor
        }
    }

    fmt.Printf("Tick interval %v and running for %v.Expected counter: %d but got %d\n", tickerInterval, tickerDuration, tickerDuration/tickerInterval, counter)
}

输出:

Tick interval 1ms and running for 10s.Expected counter: 10000 but got 9965
Tick interval 10µs and running for 10s.Expected counter: 1000000 but got 976590

【问题讨论】:

  • 我不会称它为您所缺少的“大量数字”。在您的测试中,您获得了 99% 和 97% 的预期值。
  • 感谢您的回复。但我的问题是什么是停止获得 100% 的预期值?
  • 那应该是counter++延迟
  • 我也这么认为。所以我只对这个陈述进行了基准测试。花费的时间不超过几纳秒。
  • 根据操作系统和硬件,系统时钟可能无法提供微秒精度,甚至是单毫秒精度。 Go 的计时系统自然受限于运行环境的计时系统。

标签: performance go ticker


【解决方案1】:

一般来说,当一个 API 说一个事件需要 X 秒时,它实际上保证了经过的时间将是至少 X 秒,而不是更少。特别是对于小的时间增量,这是一个重要的区别。

另外,考虑一下 NewTicker documentation 的这一点:

刻度的周期由持续时间参数指定。自动收报机将调整时间间隔或丢弃滴答声以弥补慢速接收器。

考虑到这两点,您真正拥有的唯一保证是实际滴答数将 理想情况中的预期滴答声,而其他所有情况都会少于此。

在这些小时间增量(~

  • Goroutine 调度逻辑(休眠和恢复 goroutine、线程切换)。
  • 垃圾收集(即使在循环期间没有产生垃圾,GC 可能仍然“活跃”并且偶尔会检查垃圾)

这些其他因素可能同时发生,从而更有可能跳过或延迟滴答。

把它想象成你有一个装满水的桶,你需要把它倒进另一个桶,然后另一个桶,再一个,以此类推,一千个桶。 你唯一能做的就是失去水分,一旦溢出,你将无法获得更多。在这种情况下,您永远不会期望将 100% 的水保留到最后。

这与您提到的情况相似,因为错误只向一个方向发展。延迟只能至少是指定的时间,并且只能丢失刻度(永远不会获得额外的)。每当这些事件发生时,就像失去了一滴水一样。

【讨论】:

  • 我可能仍然缺少一些东西。根据我对文档的理解,如果接收器比滴答间隔慢,ticker 应该只删除滴答声。在这种情况下,接收者只运行一个语句计数器++,它的花费不应超过 1 毫秒。我还检查了我机器中的 GC 统计信息,这可能会降低增量语句的性能,但在运行时没有执行 GC。
  • 即使没有滴答滴答被丢弃,第一点仍然很重要,即时间保证只是“至少这么多时间”,而不是“正好这么多时间”。例如,在我的机器上,将代码时间设置为低于 ~15ms 没有任何效果(它不会比 15ms 更快)。实际上,总会有一个足够小的时间间隔,以至于您无法准确地延迟该时间量。可以在很小的间隔内保持什么级别的准确度可能取决于硬件/操作系统环境。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多