【问题标题】:C# Timer for Millisecond Waits用于毫秒等待的 C# 计时器
【发布时间】:2012-04-11 02:56:31
【问题描述】:

每 n*x 毫秒我执行一个操作,其中 n = 0, 1, 2, ...; x 是一些增量。

示例 - 我每 25 毫秒执行一次计算。

对于每个增量,此操作可能需要不到 x 秒。因此,我需要一种在 C# 中的方法来等待剩余的 (x - actual_time) 毫秒。

示例 - 如果计算只需要 20 毫秒,我需要再等待 5 毫秒才能重新运行计算。

请指教。

谢谢, 凯文

【问题讨论】:

  • 精确的计时器精度有多重要?在具有上下文切换的操作系统上进行垃圾收集,在 C# 等高级语言中获得高分辨率时序将非常困难。
  • 也许您可以描述一下您认为需要执行如此高时间分辨率的操作的原因?也许有更好的方法来实现您所需要的?或者也许是一种处理时间不准确的方法?

标签: c# timer


【解决方案1】:

我需要 C# 中的一种方法来等待剩余的 (x - actual_time) 毫秒。

我猜那是在 Windows 上运行的 C#。

还有你的问题。 Windows 不是“实时”操作系统。

如果您需要毫秒级的计时精度,您可以做的最好的事情是将线程的线程优先级设置得非常高,然后在查询高性能计时器(秒表)时进行忙碌等待。

你不能屈服于另一个线程;在操作系统上下文切换它之前,另一个线程可能会运行多达 16 毫秒,当然,除非您是最高优先级的线程,否则您无法保证在这 16 毫秒结束后控制权会返回给您。

现在,将线程优先级设置为高然后忙于等待是您可能做的最粗鲁的事情之一;本质上,您将控制用户的机器,不允许他们用它做任何其他事情。

因此,我会做的是完全放弃这种做法。要么,(1)考虑获得一个专为实时过程控制而设计的操作系统,如果这实际上是您的应用程序,而不是一个专为多任务处理一堆业务线应用程序而设计的操作系统。或者 (2) 放弃您的要求,即该操作每 25 毫秒发生一次。只需执行一次计算,然后将剩余的量程交给另一个线程。当你重新获得控制权时,看看你让步后是否超过了 25 毫秒;如果没有,请再次屈服。如果有,请重新开始并执行计算。

【讨论】:

  • 现在你这么说,但我们通过打破你应该在设备驱动程序中执行的所有规则,在 Windows 上创建了一个 1 毫秒实时(在可接受的抖动容限内)系统: )
  • @Massif:Windows Vista 和更高版本使用驱动程序签名强制,这为这种方法增加了一个额外的障碍。
【解决方案2】:

在像 Windows 这样的非实时操作系统中很难达到这种精确度。您最好的选择可能是查看多媒体计时器。

其他 .NET 计时器没有您需要的分辨率。

【讨论】:

    【解决方案3】:

    在 25 毫秒时,您可能是 .Net 中可用计时器分辨率的错误方面。

    但是 - 作为一个通用的解决方案,我可能会尝试一种与您的“进行计算..等到 25 毫秒过去”方法不同的方法。

    更好的方法可能是使用System.Timers.Timer,在 25 毫秒的触发器上,触发计算。

    var timer = new Timer(25);
    timer.Elapsed += (sender, eventArgs) =>
                         {
                             DoCalc();
                         };
    timer.Start();
    

    在上面的示例中,DoCalc 方法将每 25 毫秒调用一次(尽管存在计时器分辨率问题)。你需要考虑如果你的计算overran它是分配的时间。就目前而言,上述代码将允许开始第二次计算,即使之前的计算尚未完成。

    【讨论】:

    • 我在我的机器上使用 System.Timers 的经验是,它的最大分辨率约为 15 毫秒(在 Windows XP 上),它只会在多次触发时触发。因此,如果您将其设置为 25 毫秒,您可能会得到大约 30 毫秒的间隔。当然,这可能因硬件和操作系统而异。但是,这仍然比在计算后尝试计算剩余时间并尝试按照 OP 最初建议的那样设置剩余时间的计时器更准确。
    • @MattBurland - 公平点 - 值得在目标环境上进行测试,但可能太接近分辨率而无法准确。
    【解决方案4】:

    正如 Eric Lippert 和 Matt Burland 所指出的,这是一个困难的问题,而且您的选择非常有限。基本上,你可以

    • 求助于使用多媒体计时器(谷歌“多媒体计时器组件”或“winmm.dll”),虽然它支持低至 0.500 毫秒的时间分辨率,但从 Windows Vista 开始不再推荐使用,需要 Win32 互操作并且可能会出现问题你的 CPU 使用率非常明显,或者
    • 提出一个近似的时间切片算法,该算法将使用标准计时器(在多核桌面上其分辨率通常为 15.625 毫秒),根据自上次以来经过的所需时间和实际时间的差异,在每个滴答时动态改变计时器间隔计时器滴答声(您可以使用高分辨率 CPU 性能计数器(例如 Stopwatch 类)相当准确地测量这一点)。

    后一种解决方案会在您的示例用例中统计地为您提供 40Hz 计时器,但由于您使用的计时器的分辨率较低,您会出现明显的抖动。

    这是一个折衷方案,由您决定。

    【讨论】:

      【解决方案5】:

      这是我写的一个高精度计时器。我在 25 毫秒间隔内得到大约

      链接:High Precision Timer

      【讨论】:

      • CircularBuffer 是在哪里定义的?
      • 很抱歉,是这个:circularbuffer.codeplex.com 我也在要点中添加了该评论。仅供参考
      猜你喜欢
      • 1970-01-01
      • 2015-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-02
      • 1970-01-01
      相关资源
      最近更新 更多