我认为其他的回答没有解释清楚为什么每次迭代的操作中会有14毫秒的滞后。这不是因为系统时钟不准确(而且DateTime.Now
并不不准确,除非你关闭了NTP服务或者设置了错误的时区或做了一些傻事!它只是不精确)。
精确计时器
即使使用不准确的系统时钟(使用DateTime.Now
,或将太阳能电池连接到ADC以告诉你太阳在天空中的高度,或将时间分配给高峰潮之间,等等),遵循此模式的代码将平均具有零滞后(平均每秒之间的滴答声完全准确):
var interval = new TimeSpan(0, 0, 1);
var nextTick = DateTime.Now + interval;
while (true)
{
while ( DateTime.Now < nextTick )
{
Thread.Sleep( nextTick - DateTime.Now );
}
nextTick += interval;
}
如果您复制和粘贴此代码,请注意一种情况:当您的滴答代码需要比interval
更长的时间来执行时,要小心。我将把这留给读者作为练习,以找到让其跳过尽可能多的拍子,直到nextTick
落入未来的简单方法。
计时器不准确
我猜测 Microsoft 对 System.Threading.Timer
的实现遵循这种模式。即使使用完美精确和完美准确的系统计时器(因为执行加操作也需要时间),该模式仍然会产生扭曲:
var interval = new TimeSpan(0, 0, 1);
var nextTick = DateTime.Now + interval;
while (true)
{
while ( DateTime.Now < nextTick )
{
Thread.Sleep( nextTick - DateTime.Now );
}
nextTick = DateTime.Now + interval;
}
因此,对于可能有兴趣制作自己的计时器的人,不要遵循这个第二种方法。
精确时间测量
正如其他帖子所说,Stopwatch
类提供了很高的时间测量精度,但如果遵循错误的模式,则对准确性没有任何帮助。但是,正如@Shahar所说的那样,你永远不会得到一个完美精确的计时器,因此,如果你追求完美的精度,就需要重新考虑。
声明
请注意,微软并没有谈论System.Threading.Timer
类的内部情况,所以我只是在根据我的经验猜测,但如果它像鸭子一样嘎嘎叫,那么它很可能就是一只鸭子。此外,我意识到这已经过去几年了,但这仍然是一个相关(我认为也是未回答的)问题。
编辑:将链接更改为@Shahar的答案
编辑:微软在线公开了许多东西的源代码,包括System.Threading.Timer
,供有兴趣了解微软如何实现这个衰变计时器的人参考。