- 大约有12个不同的计时器对象。
- 每个计时器都有到期时间和间隔时间,这些已正确设置。
- 观察发现,在3至4小时后,计时器开始在其间隔时间之前发出信号。例如,如果计时器应在4:59:59发出信号,则会在4:59:52提前7秒发出信号。
谢谢, Swati
很好的问题... 原因如下:
当涉及计算机时,“时间”是一件棘手的事情...你永远无法依赖于“间隔”是完美的。一些计算机只会每14到15毫秒“滴答”一次定时器,有些更频繁地执行此操作,有些则不那么频繁。
所以:
Thread.Sleep(1);
运行时间可能在1到30毫秒之间。
如果你需要更精确的计时器,你需要记录开始时间 DateTime,然后在计时器中通过DateTime.Now与原始时间进行减法操作,以确定是否“到达运行代码的时间”。
以下是所需操作的示例代码:
DateTime startDate = DateTime.Now;
然后,使用间隔设置为1毫秒启动计时器。然后,在你的方法中:
if (DateTime.Now.Subtract(startDate).TotalSeconds % 3 == 0)
{
// This code will fire every 3 seconds.
}
上面的代码将每3秒准时执行。您可以让它运行10年,它仍然会每3秒执行一次。
Timothy的解释很有说服力,但System.Threading.Timer已经按照这种方式工作。至少在Rotor实现中,它使用GetTickCount()返回的值来计算下一个回调的到期时间。真正的CLR这样做的可能性不大,更有可能使用CreateTimerQueueTimer()。然而,这个API函数也可能依赖于时钟中断递增的内部tick。
问题在于内部时钟tick(由GetTickCount()和Environment.TickCount返回)与绝对墙上时间(由DateTime.Now返回)保持同步的程度。不幸的是,这是你的机器上HAL(硬件抽象层)的实现细节。机器制造商可以提供定制的HAL,这个HAL被调整为与机器的BIOS和芯片组配合使用。
如果机器有两个计时源,一个时钟芯片设计用来跟踪墙上时间,即使你拔掉机器电源也会继续运行,另一个频率可用于分频以提供时钟中断。原始的IBM AT PC就是这样工作的。时钟芯片通常是可信的,如果不准确,时钟将严重偏差。芯片组则不能,削减振荡器质量是省钱的简单方法。
通过避免在定时器上长时间运行并在回调中从DateTime.Now重新计算下一个到期时间来解决您的问题。
这是无法控制的,因为它取决于系统的速度。如果您有超级计算机,则可能没有足够的差异,但如果您有普通PC,则在长时间执行后计时器间隔会有所不同。
希望这能帮到您。