我正在制作一个需要一些相当紧凑的时间的应用程序,而秒表类是完美的解决方案.但是,有时候我注意到,当在小型平板电脑上运行时,秒表值已经过时了.我添加了一些调试打印输出,每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操作执行时依赖于队列中的其他作业及其优先级.
这意味着计时器事件可能延迟到达,特别是如果调度员忙于其他任务.您是否将其他内容放在调度程序队列中以防止事件先前触发?
Mer*_*ham 15
期间,PC硬件上的准确时间并不简单.以下是一些资源,展示了一些Windows时序的经验,这将是Windows环境中任何计数器的底层实现,包括.NET:
它解释了为什么有时你会得到10毫秒的分辨率,这取决于你使用的系统调用,并且更多地阐明了为什么QueryPerformanceCounter是"buggy".其中一个要点是省电模式/可变CPU速度会干扰这些时序.
与此相关的概念是在实时物理模拟中"锁定时间步长".如果你谷歌那么,你可能会得到一些关于如何解决你遇到的问题的想法.基本概念是您有固定的时间步骤,并为您的计时/更新功能执行一种生产者/消费者实现.我不知道这是否适用于您的特定域名,但它被认为是视频游戏中的最佳做法.
| 归档时间: |
|
| 查看次数: |
7834 次 |
| 最近记录: |