问题 C#计时器在间隔时间之前被解雇


我们在使用时遇到了以下问题 System.Threading.Timer 来自Windows服务的(.NET 2.0)。

  1. 有大约12个不同的计时器对象..
  2. 每个计时器都有适当的时间和间隔。这是正确设置的。
  3. 观察到在3到4小时后,定时器在它们的间隔过去之前开始发信号。例如,如果计时器应该在4:59:59发出信号,则会在7秒前的4:59:52发出信号。

有人能告诉我这种行为的原因是什么,解决方案是什么?

谢谢, 斯瓦特


5920
2018-03-12 10:55


起源



答案:


好问题......这就是原因:

对于计算机而言,“时间”是一件棘手的事情......你可以 决不 依靠“间隔”来完美。有些计算机只会每隔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秒启动一次。


9
2018-03-12 11:10



我知道这只是一个例子,但你不会把定时器间隔增加到100甚至500毫秒?我知道你可能会失去一点准确性,但是当你每3秒只需要一次结果时,定时器每秒发射1000次会不会更好? - Matt Warren
是的,每秒1000次中断有点多。 - Bing Bang


答案:


好问题......这就是原因:

对于计算机而言,“时间”是一件棘手的事情......你可以 决不 依靠“间隔”来完美。有些计算机只会每隔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秒启动一次。


9
2018-03-12 11:10



我知道这只是一个例子,但你不会把定时器间隔增加到100甚至500毫秒?我知道你可能会失去一点准确性,但是当你每3秒只需要一次结果时,定时器每秒发射1000次会不会更好? - Matt Warren
是的,每秒1000次中断有点多。 - Bing Bang


蒂莫西的解释引人注目,但System.Threading.Timer已经以这种方式运作。至少在Rotor实现中,它使用GetTickCount()返回的值来计算下一个回调到期的时间。真正的CLR也不太可能这样做,它更可能使用CreateTimerQueueTimer()。然而,这个API函数也可能取决于由时钟节拍中断增加的内部节拍。

问题在于内部时钟滴答(由GetTickCount()和Environment.TickCount返回)与绝对挂起时间保持同步(由DateTime.Now返回)。不幸的是,这是您机器上硬件抽象层的HAL的实现细节。机器制造商可以提供自定义HAL,这个HAL经过调整后可以与机器的BIOS和芯片组配合使用。

如果机器有两个定时源,一个设计用于跟踪墙壁时间的时钟芯片,即使你拔掉机器电源也能保持滴答声,以及芯片组上可用的另一个频率可用于提供时钟中断。最初的IBM AT PC以这种方式工作。时钟芯片通常可以信任,如果不准确,时钟会严重关闭。芯片组不能,削减振荡器的质量是一个节省一分钱的简单方法。

通过避免计时器上的长时间段并从回调中的DateTime.Now重新计算下一个到期时间来解决您的问题。


6
2018-03-12 12:19



谢谢你的帮助。重新计算计时器可以解决我的问题。我打算试试。再次感谢 !! - Swati Ghaisas


也许重新调度是在需要几秒钟才能完成的操作之后完成的。或者你不控制这个?


0
2018-03-12 11:03





这不能控制,因为它取决于系统的速度,如果你有超级计算机,那么可能没有足够的差异,但如果你有正常的PC,那么长时间执行后定时器间隔会有差异。

希望会有所帮助。


0
2018-03-12 11:09