最近我正在寻找我的Windows应用程序的解决方案,这导致文件后面的记录不正确.. 我发现在Windows dateime.now的解决时间问题 所以,我试图避免这种情况。我根据表单答案中给出的可能提示创建了示例应用程序....
这是示例代码及其输出....
private Timer tmr = new Timer();
private Stopwatch ss;
void tmr_Tick( object sender, EventArgs e )
{
WriteData();
}
private void button1_Click( object sender, EventArgs e )
{
ss = new Stopwatch();
ss.Start();
tmr.Interval = 1;
tmr.Tick += new EventHandler( tmr_Tick );
tmr.Start();
WriteData();
}
void WriteData()
{
Console.WriteLine(ss.ElapsedMilliseconds);
}
输出: 0 19 29 49 69 79 99 109 122 142 162 172 192 202 222 232 252 282 272 294 314 334 341
如何在此代码中获得更高的准确性...... ????
答案 0 :(得分:3)
tmr.Interval = 1;
这是一个很小的数字,一些不能使它变小的美德。但不,你不会得到一个计时器每秒嘀嗒一千次。有三个因素决定了Timer触发Tick事件的实际速率:
你的UI线程在做其他事情的忙碌程度。就像运行Click事件处理程序或绘制窗口一样。 Tick事件处理程序只能在UI线程不忙于任何事情时运行,它必须空闲。这当然是一个高度可变的数字,这对你的应用程序的用户来说非常重要。他可以做的一些事情非常昂贵,比如调整应用程序窗口的大小。典型的UI线程职责,如绘画,需要花费几毫秒。对于人眼而言足够快,但如果您需要经常运行Tick事件,则非常明显。如果您的用户界面错综复杂,它就不会运行,可能会持续数百毫秒。您需要一种不同类型的Timer类来避免这种情况,System.Threading.Timer或System.Timers.Timer。它们是在线程池线程上运行其代码的计时器类。它的优点是它不会被UI线程中发生的事情延迟。而且你必须非常小心你在该代码中所做的显着缺点,你肯定无法更新UI。
机器在做其他事情的忙碌程度。就像执行另一个进程或设备驱动程序的线程一样。这是操作系统的主要任务,允许数百个线程共享处理器。 Windows中的线程调度程序确定线程何时有机会运行。一旦它获得处理器并执行,就可以运行一段时间,称为量子。对于前景中的窗口拥有的线程,典型的量子是45毫秒。其他线程暂停直到他们有机会运行。这当然会让你计划每秒运行一次Tick事件的计划毁灭了。你需要仔细控制机器上运行的其他程序,多核处理器会有很大的帮助。
Windows更新计时器的频率。与之相关的核心操作系统功能是时钟中断。用于很多事情,它是操作系统的基本心跳。处理器的正常状态是不做任何事情,它被关闭。时钟节拍中断将其从暂停状态唤醒,操作系统会检查是否需要执行任何工作。默认中断率是每秒64次,每15.625毫秒一次。这也会影响定时器的准确性,处理器暂停时不会发生任何事情。因此,按照设计,你将永远不会获得1毫秒的速率,它永远不会少于16毫秒。
后一个子弹当然是最大的挂断。实际上,您可以更改程序中的中断率,它需要对timeBeginPeriod()winapi函数进行pinvoke调用。 This answer显示了如何。还提到了timeSetEvent()函数,你需要在一个接近定时器的位置,它能够保证能够维持1毫秒的速率。
答案 1 :(得分:2)
秒表使用Windows性能计数器API,因此它应该非常准确(性能计数器API被引用为具有低微秒范围内的分辨率)。
但是,您的测试无效,因为您实际上是在测量计时器中的漂移而不是秒表中的任何不准确。
关于Timer的主题 - 看起来你正在使用样本中的System.Windows.Forms.Timer类。这不是精确度的绝佳选择;它的唯一优势是它会在UI线程上引发Tick事件。请尝试使用System.Threading.Timer类 - 您可能会发现它可以使结果更接近您的预期(尽管仍有一些偏差)。
var timerCallback = (TimerCallback)(sw => Console.WriteLine(((Stopwatch)sw).Elapsed));
var timerInterval = TimeSpan.FromMilliseconds(1);
var stopwatch = Stopwatch.StartNew();
var timer = new Timer(timerCallback, stopwatch, timerInterval, timerInterval);
最终测试秒表的准确性非常困难,因为没有其他任何现成的东西更准确!