【问题标题】:Inconsistent intervals with System.Windows.Forms.TimerSystem.Windows.Forms.Timer 的间隔不一致
【发布时间】:2014-09-16 18:51:44
【问题描述】:

请客气,我刚刚学习 C#,从前雇员那里继承这个应用程序是我的第一个 C# 项目。

我观察到 System.Windows.Forms.Timer 的周期不一致且缓慢。该应用程序是用 C# 和 MS Visual Studio 编写的。

计时器设置为 100 毫秒的间隔,但我观察到的周期范围从 110 毫秒到 180 毫秒。

我正在使用多种工具来观察这一点,包括: - 软件示波器(Iocomp.Instrumentation.Plotting.Plot 包), - 一个真正的示波器, - 让计时器运行一段时间并将滴答数 * 100 毫秒与系统时间和秒表进行比较。

在所有情况下,我都观察到 10% 的延迟,在最初的几秒钟内就变得很明显。

每个刻度执行的方法运行时间少于 4 毫秒。也不会发生耗时的异步处理。不过,这无关紧要,因为计时器滴答是一个中断,而不是添加到事件处理程序队列中的事件(据我所知)。

以前有没有人遇到过这样的问题?根本原因是什么?

谢谢。

【问题讨论】:

  • 看起来这个问题已经被 Andre Saffin click here for the link解决了
  • 感谢您的回复。我很感激。

标签: c# timer period frequency-analysis


【解决方案1】:

定时器仅与操作系统时钟中断一样准确。默认情况下每秒滴答 64 次,即 15.625 毫秒。你不能从中得到一个干净的 100 毫秒间隔,它不能被 15.625 整除。你得到下一个整数倍数,7 x 15.625 = 109.375 毫秒。非常接近您观察到的 110 毫秒。

您需要将处理计时器通知的延迟添加到这个理论最小值。计时器必须与 UI 线程中发生的所有其他事情竞争。它们被视为要发送的最不重要的通知。发送消息在前,用户输入在后,绘画在后,定时器消息在后。无论哪种方式,如果您有一个精心设计的用户界面需要一段时间来重新绘制,那么 Tick 事件将被延迟,直到完成。对于您编写的任何不平凡的事件处理程序(例如读取文件或查询数据库)也是如此。

要获得不受这种延迟影响的响应速度更快的计时器,您需要使用异步计时器。 System.Threading.Timer 或 System.Timers.Timer。避免后者。他们的回调在线程池线程上运行,因此可以很快运行。要非常小心你在这个回调中所做的事情,很多事情你不能做,因为它们不是线程安全的。

您可以通过更改时钟中断率使这些计时器更准确。这需要 pinvoke,调用 timeBeginPeriod()。完成后的 timeEndPeriod()。

【讨论】:

  • 哇,很棒的回应,汉斯。非常感谢您的解释。
【解决方案2】:

是的,我总是遇到 System.Windows.Forms.Timer 的这个问题,因为它不能准确地滴答(大部分时间)。 你可以试试System.Timers.Timer,它会精确地引发中断(至少100毫秒的精度)

【讨论】:

    【解决方案3】:

    System.Windows.Forms.Timer 实际上只是原生 WM_TIMER 消息的包装器。这意味着定时器消息被放置在消息队列中的时间大致接近您请求的时间间隔(加或减......这里没有保证)。 何时处理该消息完全取决于队列中的其他消息以及每个消息的处理时间。例如,如果您阻止 UI 线程(从而阻止队列处理新消息),则在取消阻止之前您不会收到计时器事件。

    Windows 不是实时操作系统,您不能指望计时器具有细粒度的准确性。如果您想要更细粒度的东西,多媒体计时器是最佳选择。

    【讨论】:

    • 感谢您的回复,彼得。我知道 Windows 不是 RTOS,只是没有意识到它是多么不实时。我只在具有 RTOS 或我自己编写的中断/队列机制的嵌入式设备上工作过。信任 Windows 对我来说是全新的体验。
    【解决方案4】:

    这是旧的,但如果有人来这里寻找一个真正正确的答案:

    来自https://msdn.microsoft.com/en-us/library/system.windows.forms.timer(v=vs.110).aspx(强调我的):

    Windows 窗体计时器组件是单线程的,并且被限制为55 毫秒的精度。如果您需要更准确的多线程计时器,请使用 System.Timers 命名空间中的 Timer 类。

    所以使用 Windows.Forms.Timer 可以获得 55ms、110ms、165ms 等;这与您所看到的一致。如果您需要更高的精度,请尝试System.Timers.TimerSystem.Threading.Timer

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-04
      • 2012-01-29
      • 2021-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多