.NET秒表类可以这么糟糕吗?

Bab*_*oey 17 .net stopwatch

我正在制作一个需要一些相当紧凑的时间的应用程序,而秒表类是完美的解决方案.但是,有时候我注意到,当在小型平板电脑上运行时,秒表值已经过时了.我添加了一些调试打印输出,每200毫秒左右监视一次秒表的值:

0:00:197
0:00:502
0:00:702
...
0:03:356
0:12:93

0:13:21
0:13:421
...

它怎么可能从~3秒跳到~13秒?我现在看到底层函数QueryPerformanceCounter()是错误的(小心QueryPerformanceCounter()),但我感觉到其他东西在这里发生了.

任何见解都表示赞赏.

更新:

这里有关于我的代码的更多细节:它非常简单.它是一个WPF应用程序,它Stopwatch在启动时创建一个新对象,然后通过它启动它Start().我然后创建一个DispatcherTimer,像这样:

displayTimer = new DispatcherTimer(); 
displayTimer.Tick += display_Tick; 
displayTimer.Interval = DISPLAY_INTERVAL_TIMESPAN; 
Run Code Online (Sandbox Code Playgroud)

时间跨度为200毫秒.我的调试代码只是在Stopwatch每次dispatchTimer滴答时打印出对象的值.

UPDATE2:

一个有趣的Microsoft支持文章是性能计数器值可能意外地向前飞跃.

Dir*_*mar 17

更新(看到你的日志后)

正如您已经提到的,Stopwatch该类使用QueryPerformanceCounter下面的函数.在备注部分,MSDN说:

在多处理器计算机上,调用哪个处理器无关紧要.但是,由于基本输入/输出系统(BIOS)或硬件抽象层(HAL)中的错误,您可以在不同的处理器上获得不同的结果.要指定线程的处理器关联,请使用SetThreadAffinityMask函数.

在使用Dispatcher时,QueryPerformanceCounter每次查询经过的时间时,可能不会在同一CPU上执行.

您可以通过为进程指定处理器关联,例如通过使用start命令调用可执行文件来检查MSDN中提到的问题是否是您遇到问题的原因.10秒似乎是CPU与我之间的一个很大的滞后,但文档对于差异有多大是非常模糊的.以下命令将您的应用程序绑定到第一个CPU:

> start.exe /AFFINITY 1 program.exe
Run Code Online (Sandbox Code Playgroud)

如果这应解决问题,您可能需要查看建议的解决方法,即SetThreadAffinityMask在查询Stopwatch对象之前调用该函数.

您的评论说您使用的是WPF DispatcherTimer.该类的文档说明:

定时器不能保证在时间间隔发生时准确执行,但保证在时间间隔发生之前不执行定时器.这是因为DispatcherTimer操作与其他操作一样放在Dispatcher队列中.DispatcherTimer操作执行时依赖于队列中的其他作业及其优先级.

这意味着计时器事件可能延迟到达,特别是如果调度员忙于其他任务.您是否将其他内容放在调度程序队列中以防止事件先前触发?

  • @Tim:好的,这实际上是一个重要的事实,你在嵌入式系统而不是普通的台式PC上观察到这一点.由于时钟毕竟基于硬件,因此最有可能造成硬件错误. (3认同)

Mer*_*ham 15

期间,PC硬件上的准确时间并不简单.以下是一些资源,展示了一些Windows时序的经验,这将是Windows环境中任何计数器的底层实现,包括.NET:

它解释了为什么有时你会得到10毫秒的分辨率,这取决于你使用的系统调用,并且更多地阐明了为什么QueryPerformanceCounter是"buggy".其中一个要点是省电模式/可变CPU速度会干扰这些时序.

与此相关的概念是在实时物理模拟中"锁定时间步长".如果你谷歌那么,你可能会得到一些关于如何解决你遇到的问题的想法.基本概念是您有固定的时间步骤,并为您的计时/更新功能执行一种生产者/消费者实现.我不知道这是否适用于您的特定域名,但它被认为是视频游戏中的最佳做法.

  • @Tim:这是最接近猜测问题的人.你必须展示一些最小的代码来解决问题,并提供有关你的环境的细节让我们停止猜测:) (5认同)
  • 十秒钟可能"相当疯狂",但如果GC开始,它很有可能. (4认同)
  • 10毫秒的分辨率对我来说很好......我看到秒表课的前进了10秒. (2认同)
  • 也许,只是可能,10秒实际通过?你的程序实际上做了什么? (2认同)