哪些定时器依赖于系统时间?

18

我还没有测试过这个。希望已经有人知道答案,这样我就不必写一个测试应用程序了,否则我会写的。:)

通常情况下,当我想比较时间时,我只是存储DateTime.Now并在以后比较它。我认为当用户在中间更改用户系统时间时,这会导致错误的结果。

这让我想知道计时器是否表现出相同的方式。哪些.NET计时器依赖于设置的系统时间?考虑启动需要在一小时内到期的计时器。当我将系统时间向前调整一小时时,它会触发吗?

我从来没有真正关心过这种可能的行为,但在某些情况下它可能很重要。哪些计时器对此场景是安全的,哪些则绝对不是?


如果您有查询NTP服务器的自由,您可以使用类似于此NTP类的简单工具。 - Bala R
谢谢您的建议,但对于本地解决方案来说,那可能有点过头了。 :) - Steven Jeuris
6
所有计时器都不依赖于系统时间。也就是说,用户更改时钟不会影响 System.Windows.Forms.Timer, System.Timers.Timer, 或 System.Threading.Timer,也不会影响 StopwatchEnvironment.TickCount。此外,使用 Stopwatch 没有任何“额外开销”。它的值不会不断更新,而是惰性地评估(即只有在引用 Ticks 时才会更新)。 - Jim Mischel
@JimMischel,这个信息在MSDN或者“官方”来源中有吗? - Ofiris
@Ofiris:秒表的文档说明:“秒表通过计算底层计时器机制中的计时器滴答声来测量经过的时间。如果安装的硬件和操作系统支持高分辨率性能计数器,则秒表类使用该计数器来测量经过的时间。”如果您查找有关高分辨率性能计数器的信息,您会发现它不依赖于系统时间。 - Jim Mischel
1
@Ofiris:计时器非常相似。System.Threading.Timer 基于 Windows Timer Queue Timers,可以查看相关文档。System.Timers.Timer 只是 System.Threading.Timer 的一个包装器。System.Windows.Forms.Timer 是围绕 Windows 的 SetTimerKillTimer 函数编写的包装器。对于这些函数的文档表明,它们不依赖于系统时间。 - Jim Mischel
3个回答

6

我曾试图解决类似的问题。结果我使用System.Diagnostic.StopWatch来替换所有的DateTime.Now。如果有高频率时钟,StopWatch将使用它,所以它更准确,而且不受系统时钟改变的影响。但是,如果没有高频率时钟,则会再次回到系统时钟。

根据我的测试,我所有的计算机都有高频率时钟,包括虚拟机中的计算机。

关于定时器,据我所记,它不依赖于系统时钟。不过,你真的不想使用定时器来跟踪时间,因为定时器的回调事件可能会被一些其他事件推迟。


1
@Steven 三个计时器类在一段时间后都会调用您的回调函数或触发事件。System.Windows.Form.Timer 应该使用 WM_TIMER,它与其他 Windows 消息共享同一个消息循环。这就是我的意思。对于其他计时器类,我只尝试了 System.Timers.Timer,看起来它不依赖于系统时钟。 - Harvey Kwok
1
“秒表”应该是低开销的,因为它不需要计算年/月/日信息,它只是经过的时间。 - Ben Voigt
2
在许多现代(又称廉价)主板上,Stopwatch.ElapsedTicks是从芯片组时间源生成的,该时间源具有很高的分辨率,但精度非常差。它不能替代定时器,后者运行于时钟滴答中断上,并校准了一个互联网时间服务器校正。 Stopwatch仅适用于比较短的时间间隔。 - Hans Passant
2
@Steven:CPU中有一个独立的电路,以及主板上的一块芯片,专门用于高分辨率计时。这不会增加额外的开销,也不会让CPU更频繁地运行计时处理代码。 - Ben Voigt
@Hans:秒表根本没有任何准确性。它只能计算经过的时间,甚至不能报告绝对时间。如果Windows在使用具有可变时钟速率的CPU上作为其精度时间源,则这是Windows的错误。我认为它足够聪明,会使用计时器芯片代替。时钟中断并未与互联网时间校准(每个中断计算的经过时间可能已经校准,但中断本身不受任何影响)。 - Ben Voigt
显示剩余6条评论

4

我只会引用Jim Mischel的评论,因为它是对我的问题最相关的答案。

没有任何一个定时器依赖于系统时间。也就是说,用户更改时钟不会影响System.Windows.Forms.Timer、System.Timers.Timer或System.Threading.Timer。也不会影响Stopwatch或Environment.TickCount。此外,使用Stopwatch没有任何“开销”。它不像值会持续更新。它是惰性评估的(即在引用时更新Ticks)。 Stopwatch的文档说:“Stopwatch通过计算底层计时器机制中的计时器滴答声来测量经过的时间。如果安装的硬件和操作系统支持高分辨率性能计数器,则Stopwatch类使用该计数器来测量经过的时间。”如果您查找有关高分辨率性能计数器的信息,您将看到它不依赖于系统时间
定时器是类似的。System.Threading.Timer基于Windows计时器队列计时器。请参阅该文档。System.Timers.Timer只是System.Threading.Timer的包装器。System.Windows.Forms.Timer是Windows SetTimer和KillTimer函数的包装器。这些的文档表明它们不依赖于系统时间。

0
在 RPi Zero 上,我看到的是这样的: 如果更改系统时钟,Thread.Sleep 将停止工作。如果将时间设置为当前时间之前的某个值,然后再将其设置回来,Sleep 将不再起作用。如果将时间设置为过去的某个时间,然后再次设置为当前时间,它将按预期工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接