简体   繁体   English

毫秒等待的C#计时器

[英]C# Timer for Millisecond Waits

Every n*x milliseconds I perform an action where n = 0, 1, 2, ...; 我每n * x毫秒执行一次操作,其中n = 0、1、2,...; x is some increment. x是一个增量。

Example - every 25 milliseconds I perform a calculation. 示例-我每25毫秒执行一次计算。

This action can take fewer than x seconds for each increment. 对于每个增量,此操作可能少于x秒。 As a result, I need a way in C# to wait the remaining (x - actual_time) milliseconds. 结果,我需要一种C#方法来等待剩余的(x-Actual_time)毫秒。

Example - if the calculation only takes 20 milliseconds, I need to wait 5 more milliseconds before re-running the calculation. 示例-如果计算仅花费20毫秒,那么我需要再等待5毫秒才能重新运行计算。

Please advise. 请指教。

Thanks, Kevin 谢谢,凯文

I need a way in C# to wait the remaining (x - actual_time) milliseconds. 我需要一种在C#中等待剩余(x-Actual_time)毫秒的方法。

I presume that is C# running on Windows. 我认为这是Windows上运行的C#。

And there is your problem. 还有你的问题。 Windows is not a "realtime" operating system. Windows不是“实时”操作系统。

The best you can do if you need millisecond-grade timing precision is to set the thread priority of your thread extremely high, and then busy-wait while querying the high performance timer (Stopwatch). 如果需要毫秒级的计时精度,最好的办法就是将线程的线程优先级设置得很高,然后在查询高性能计时器(Stopwatch)时忙于等待。

You cannot yield to another thread ; 您不能屈服于另一个线程 the other thread could run for as much as 16 milliseconds before the operating system context switches it, and of course unless you are the highest priority thread, you have no guarantee that control is coming back to you after those 16 milliseconds are up. 另一个线程可能会在操作系统上下文切换之前最多运行16毫秒,当然,除非您是优先级最高的线程,否则您无法保证在这16毫秒用完后,控制权将重新归还给您。

Now, setting thread priority high and then busy waiting is one of the most rude things you can possibly do; 现在,将线程优先级设置为高然后忙于等待是您可能要做的最不礼貌的事情之一。 essentially you will be taking control of the user's machine and not allowing them to do anything else with it. 本质上,您将控制用户的机器,而不允许他们用它做任何其他事情。

Therefore what I would do is abandon this course of action entirely . 因此,我要做的就是完全放弃这一行动方针 Either, (1) consider obtaining an operating system designed for realtime process control if that is in fact your application, rather than an operating system designed for multitasking a bunch of line-of-business applications. (1)可以考虑获得一个设计用于实时过程控制的操作系统(如果实际上是您的应用程序),而不是设计用于对多个业务线应用程序进行多任务处理的操作系统。 Or (2) abandon your requirement that the action happen exactly every 25 milliseconds. 或(2)放弃您的要求,即每25毫秒准确执行一次操作。 Just perform the calculation once and yield the remainder of your quantum to another thread. 只需执行一次计算,然后将剩余的量子分配给另一个线程。 When you get control back, see if more than 25 ms has passed since you yielded; 当您重新获得控制权时,请查看自从您屈服以来是否经过了25毫秒以上的时间; if it has not, yield again. 如果没有,请再次屈服。 If it has, start over and perform the calculation. 如果有,请重新开始并执行计算。

That level of accuracy will be very difficult to achieve in a non real-time operating system like Windows. 在非实时操作系统(如Windows)中,要达到这样的精度水平将非常困难。 Your best bet might be to look into the multimedia timers. 最好的选择是查看多媒体计时器。

The other .NET timers won't have the kind of resolution your need. 其他.NET计时器将没有您需要的分辨率。

Here's a high-precision timer I wrote. 这是我写的高精度计时器。 I get roughly <1ms avg precision on 25ms interval. 我在25ms的间隔内获得大约<1ms的平均精度。 But if Windows is busy it may come in late. 但是,如果Windows繁忙,它可能会迟到。 It's fairly lean on CPU utilization. 它相当依赖于CPU利用率。 Feel free to use. 随时使用。 It uses Sleep(1) when the next tick is more than 15ms away and then SpinUntil (which yields as needed) to keep CPU usage at bay. 当下一个刻度距超过15毫秒时,它将使用Sleep(1),然后使用SpinUntil(根据需要产生)以保持CPU使用率稳定。 Uses .NET4 features. 使用.NET4功能。

Link: High Precision Timer 链接: 高精度计时器

At 25ms, you may be the wrong side of the resolution of your available timers in .Net. 在25毫秒时,您可能会错失.Net中可用计时器的分辨率。

However - as a general solution I'd probably attempt this a different way to your "do calculation..wait until 25ms has passed" approach. 但是,作为一般解决方案,我可能会尝试采用另一种方式来进行“进行计算..等到25毫秒过去”。

A better way may well be to use a System.Timers.Timer , on a 25ms trigger, to trigger the calculation. 更好的方法可能是在25ms的触发器上使用System.Timers.Timer触发计算。

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

In the above example, a DoCalc method will be called every 25 ms (timer resolution issues notwithstanding). 在上面的示例中,每25毫秒将调用一次DoCalc方法(尽管存在计时器分辨率问题)。 You would need to consider what to do if your calculation overran it's allotted time though. 但是,如果您的计算超出了分配的时间,则需要考虑该怎么做。 As it stands, the above code would allow a second calculation to start, even if the previous had not completed. 就目前而言,即使之前的代码尚未完成,上述代码也将允许第二次计算开始。

This is a difficult one, and your options are fairly limited, as Eric Lippert and Matt Burland indicate. 正如Eric Lippert和Matt Burland所说,这是一个困难的选择,而且您的选择还很有限。 Basically, you can either 基本上,您可以

  • resort to using multimedia timers (google "multimedia timer component" or "winmm.dll"), which, although supporting time resolutions down to 0.500 ms, are no longer recommended as of Windows Vista, require Win32 interop and may bump up your CPU usage quite noticeably, or 诉诸使用多媒体计时器(谷歌“多媒体计时器组件”或“ winmm.dll”),尽管它支持的时间分辨率低至0.500毫秒,但从Windows Vista开始不再建议使用,它需要Win32互操作性,并且可能会增加CPU使用率相当明显,或者
  • come up with an approximated time slicing algorithm that will use the standard timer (whose resolution is usually 15.625 ms on multicore desktops), dynamically varying the timer interval upon each tick based on the difference of desired and actual time elapsed since the last timer tick (you can measure this fairly accurately using high resolution CPU performance counters, eg the Stopwatch class). 提出一种近似的时间分片算法,该算法将使用标准计时器(在多核台式机上,其分辨率通常为15.625毫秒),并根据自上次计时器滴答后的期望时间与实际时间之差,在每个滴答时动态更改计时器间隔(您可以使用高分辨率CPU性能计数器(例如Stopwatch类)相当准确地进行测量。

The latter solution will statistically give you a 40Hz timer in your sample use case, but you'll have significant jitter due to the low resolution of the timer you are using. 后一种解决方案在示例用例中将统计地为您提供40Hz计时器,但由于所用计时器的分辨率较低,因此您会产生明显的抖动。

This is the tradeoff, the call is yours to make. 这是折衷方案,您可以自己拨打电话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM