总的说几句:
定时器合并提供了一种减少中断数量的方法。允许应用程序为其时序要求指定容差。这允许操作系统“批量”中断并产生以下后果:
- 中断的数量可能会减少。(+)
- 上下文切换的数量可能会更少。(+)
- 功耗可能会降低。(+)
- 可能必须在那些批处理中断处完成大量操作 (-)
- 调度器此时可能不得不调度大量进程 (-)
- 时间分辨率更差(-)
Windows 以及其他基于中断的操作系统总是“批处理”定时事件。任何设置为在特定时间发生的事情都依赖于中断到期的到期时间。因此,事件与中断合并。该方案的粒度由中断频率决定。对计时器合并感兴趣的人必须阅读:MSDN:Windows 计时器合并。
出于性能原因,应尽一切努力尽可能减少中断的数量。不幸的是,许多软件包确实将系统计时器分辨率设置得非常高,例如通过多媒体计时器接口timeBeginPeriod
/timeEndPeriod
或底层 API NtSetTimerResolution
。就像 Hans 提到的:“Chrome”是一个很好的例子,说明这些功能的使用是如何被严重夸大的。
其次,现在我开始想…… timeSetEvent
是多媒体定时器功能之一。它timeBeginPeriod
在引擎盖下使用。
而且它使用得很糟糕:它设置系统计时器分辨率以在执行平台上可用的计时器分辨率内尽可能好地匹配uResolution 。在较大的uDelay值上,它可以以低分辨率等待,直到接近延迟到期,然后才提高系统计时器分辨率,但它将整个等待周期的计时器分辨率设置为指定的uResolution。这很痛苦,因为知道高分辨率也适用于长时间的延迟。然而,多媒体定时器功能不建议在大延迟下使用。但是一遍又一遍地设置分辨率也不好(见下面的注释)。
总结timeSetEvent
:这个函数根本没有做任何像合并这样的事情,它做的恰恰相反:它选择性地增加了中断的数量;从这个意义上说,它将事件传播到更多的中断上,它“分批”它们。
SetThreadpoolTimer
首次引入了“批处理”事件的概念。这主要是由于对 Windows 笔记本电脑电池续航时间的抱怨越来越多。SetWaitableTimerEx
进一步推动了该策略,并且SetCoalescableTimer
是访问合并计时器的最新 API。后者引入了 TIMERV_DEFAULT_COALESCING 和 TIMERV_NO_COALESCING 值得考虑,因为它们允许忽略某些事实。
借此机会对系统计时器分辨率进行一些说明:
改变系统定时器的分辨率比增加中断频率有更多的后果。使用timeBeginPeriod
/带来的一些影响NtSetTimerResolution
:
- 中断频率变化
- 线程量子变化(线程时间片)(!)
- 系统时间打嗝(MSDN:“...频繁调用会显着影响系统时钟”)
- 系统时间调整处于活动状态时打嗝 (
SetSystemTimeAdjustment
)
第 3 点在 Windows 7 中得到部分处理,第 4 点仅在 Window 8.1 中得到解决。系统时间的中断可能与支持的最小计时器分辨率(典型系统上为 15.625 毫秒)一样大,并且它们在何时timeBeginPeriod
/NtSetTimerResolution
频繁地累积。当尝试调整系统时间以匹配 NTP 参考时,这可能会导致相当大的跳跃。在 Windows 版本 < Windows 8 上运行时,NTP 客户端需要以高计时器分辨率运行以获得合理的准确性。
最后:只要 Windows 看到这样做的好处,它就会更改系统计时器的分辨率。支持的计时器分辨率的数量取决于底层硬件和 Windows 版本。可用分辨率的列表可以通过扫描它们来获得,方法是调用timeBeginPeriod
增加周期,然后调用NtQueryTimerResolution。Windows 在特定平台上可能“不喜欢”某些受支持的分辨率,并对其进行修改以更好地满足 Windows 需求。示例:XP 可能会在某些平台上短时间后将大约 4 毫秒的“用户设置”分辨率更改为 1 毫秒。特定的 Windows 版本 < 8.1 确实会在不可预测的时间更改计时器分辨率。
如果要求应用程序完全独立于这些人工制品,则它必须自行获得最高可用分辨率。这样,应用程序就控制了系统范围的分辨率,并且不必担心其他应用程序或操作系统更改计时器分辨率。更现代的平台确实支持 0.5 毫秒的计时器分辨率。timeBeginPeriod
不允许获取此分辨率,但NtSetTimerResolution可以。在这里,我描述了如何使用 NtSetTimerResolution 来获得 0.5 毫秒的分辨率。
在这种情况下,功耗可能会增加,但这是为可靠分辨率支付的费用:在现代硬件上,上下文切换的能量成本通常为 0.05 mJ 到 0.2 mJ(有没有人估计全球每年的上下文切换总量? )。Windows 将线程量子(时间片)削减到大约。定时器分辨率设置为最大值时的 2/3。结果,功耗增加了大约。30%!