对于我正在进行的项目,我需要每秒执行一些逻辑(几乎)10次。我知道非实时操作系统的限制,偶尔可以说10-20%的余量是可以的;也就是说,循环之间偶尔会有120毫秒的延迟。但是,重要的是我绝对可以保证周期性的逻辑执行,并且不会出现超出上述余量的延迟。这似乎很难在C#中实现。
我的情况如下:在应用程序启动后的某个时间,触发一个将启动逻辑执行周期的事件。当该循环运行时,该程序还处理其他任务,如通信,日志记录等。 我需要能够在Windows上使用.NET运行程序,在Linux上运行Mono。这不包括导入winmm.dll作为使用其高精度计时功能的可能性。
到目前为止我尝试了什么:
到目前为止,最好的选择似乎是使用System.Timers.Timer类。为了纠正上面提到的109毫秒,我将间隔设置为92毫秒(这看起来非常hacky ......!)。然后,在事件处理程序中,我使用秒表计算实际经过的时间,然后根据该计算执行我的系统逻辑。
在代码中:
var timer = new System.Timers.Timer(92);
timer.Elapsed += TimerElapsed;
timer.AutoReset = true;
timer.Start();
while (true){}
处理程序:
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
var elapsed = _watch.ElapsedMilliseconds;
_watch.Restart();
DoWork(elapsed);
}
然而,即使采用这种方法,偶尔也会发生事件仅在超过200毫秒后被触发,达到> 500毫秒(单声道)。这意味着我错过了一个或多个逻辑执行周期,这可能是有害的。
有没有更好的方法来解决这个问题?或者这个问题是操作系统工作方式所固有的问题,并且没有更可靠的方法可以在没有高CPU负载的情况下以稳定的间隔执行重复逻辑执行吗?
答案 0 :(得分:1)
与此同时,我能够在很大程度上解决这个问题。
首先,我对问题中引用的计时器的CPU使用情况进行了更正。 CPU使用率是由我自己的代码引起的,我使用了紧张的while循环。
我发现这一点后,我能够通过使用两个计时器来解决问题,并在运行时检查环境的类型,以决定实际使用哪个。为了检查环境,我使用:
private static readonly bool IsPosixEnvironment = Path.DirectorySeparatorChar == '/';
在Linux下通常是正确的。
现在,可以使用两个不同的计时器,例如Windows的this one和Linux的this one,如下所示:
if (IsPosixEnvironment)
{
_linTimer = new PosixHiPrecTimer();
_linTimer.Tick += LinTimerElapsed;
_linTimer.Interval = _stepsize;
_linTimer.Enabled = true;
}
else
{
_winTimer = new WinHiPrecTimer();
_winTimer.Elapsed += WinTimerElapsed;
_winTimer.Interval = _stepsize;
_winTimer.Resolution = 25;
_winTimer.Start();
}
到目前为止,这给了我很好的结果;步长大小通常在99-101 ms范围内,间隔设置为100 ms。而且,更重要的是,对于我的目的,没有更长的间隔。
在一个较慢的系统(Raspberry Pi第一代模型B)上,我偶尔会有更长的间隔,但在得出结论之前我必须首先检查整体效率。
还有this timer,它在两个操作系统下都是开箱即用的。在测试程序中,与之前链接的测试程序相比,这个在Linux下使用Mono导致了更高的CPU负载。