【问题标题】:Timers differences between Win7 & Win10Win7和Win10的定时器区别
【发布时间】:2025-11-28 21:50:01
【问题描述】:

我有一个应用程序,我使用 gettimeofday 的 MinGW 实现在 Win7 上实现“精确”计时(~1ms 精度)。它工作正常。

但是,当在 Win10 上使用相同的代码(甚至是相同的 *.exe)时,精度急剧下降到著名的 15.6ms 精度,这对我来说还不够。

两个问题: - 你知道造成这种差异的根源是什么吗? (它是操作系统配置/“功能”吗?) - 我该如何解决?或者,更好的是,是否有一个与操作系统配置无关的精确计时器?

注意:std::chrono::high_resolution_clock 似乎也有同样的问题(至少它确实显示了 Win10 的 15.6 毫秒限制)。

【问题讨论】:

  • 15.6 是正常值,这是您的 Win7 安装行为异常。调用 timeBeginPeriod() 或使用 QueryPerformanceCounter() 来获得亚微秒级的分辨率。 QPF 是最好的。
  • “不当行为”如何表现得更好?这是否来自配置选项?
  • 正常和“更好”有相反的目标。电源使用很粗糙,你会很快耗尽笔记本电脑的电池。不是配置,通常是调用 timeBeginPeriod() 的程序或驱动程序。 Chrome is notorious for doing this。运行 powercfg -energy 找到 Win7 上的麻烦制造者。
  • 哦,根据我对我测试过的各种不同计算机配置的了解,电源使用设置很有意义。您的组合 cmets 回答了我问题的所有方面。谢谢。

标签: c++ c++11 windows-7 mingw windows-10


【解决方案1】:

来自 Hans Passant cmets 和我这边的其他测试,这是一个更合理的答案:

Windows 上的 15.6 毫秒(1/64 秒)限制为 well-known,是默认行为。可以降低限制(例如,通过调用timeBeginPeriod() 降低到 1 毫秒)虽然我们不建议这样做,因为这会影响全局系统计时器分辨率和生成的power consumption。例如,Chrome is notorious for doing this‌​。因此,由于计时器分辨率的全局性,人们可能会在没有明确要求的情况下观察到 1ms 的精度,因为第三方程序。

此外,请注意 std::chrono::high_resolution_clock 确实 not 在 Windows 上具有有效行为(在 Visual Studio 或 MinGW 上下文中)。所以你不能指望这个接口是一个跨平台的解决方案,15.625ms的限制仍然适用。

知道了,我们该如何处理呢?好吧,可以使用timeBeginPeriod() 来提高某些计时器的精度,但同样,我们不建议这样做:使用QueryPerformanceCounter() (QPC) 似乎更好,这是根据微软的说法,本机代码的主要 API 期待 acquire high-resolution time stamps or measure time intervals。请注意GPC does count elapsed time (and not CPU cycles)。这是一个使用示例:

LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds;
LARGE_INTEGER Frequency;

QueryPerformanceFrequency(&Frequency); 
QueryPerformanceCounter(&StartingTime);

// Activity to be timed

QueryPerformanceCounter(&EndingTime);
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;


//
// We now have the elapsed number of ticks, along with the
// number of ticks-per-second. We use these values
// to convert to the number of elapsed microseconds.
// To guard against loss-of-precision, we convert
// to microseconds *before* dividing by ticks-per-second.
//

ElapsedMicroseconds.QuadPart *= 1000000;
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;

根据Microsoft,QPC 也适用于多核/多线程环境,尽管它可能不太精确/不明确:

当您比较从不同线程获取的性能计数器结果时,请考虑相差 ± 1 个刻度的值具有不明确的顺序。如果时间戳取自同一线程,则此 ± 1 滴答不确定性不适用。在此上下文中,术语滴答指的是等于 1 ÷(从QueryPerformanceFrequency 获得的性能计数器的频率)的时间段。

作为附加资源,MS 还提供了FAQ on how/why use QPC 和对clock/timing in Windows 的解释。

【讨论】:

    最近更新 更多