C#.NET / Mono

时间:2017-07-14 09:00:23

标签: c# timer mono

对于我正在进行的项目,我需要每秒执行一些逻辑(几乎)10次。我知道非实时操作系统的限制,偶尔可以说10-20%的余量是可以的;也就是说,循环之间偶尔会有120毫秒的延迟。但是,重要的是我绝对可以保证周期性的逻辑执行,并且不会出现超出上述余量的延迟。这似乎很难在C#中实现。

我的情况如下:在应用程序启动后的某个时间,触发一个将启动逻辑执行周期的事件。当该循环运行时,该程序还处理其他任务,如通信,日志记录等。 我需要能够在Windows上使用.NET运行程序,在Linux上运行Mono。这不包括导入winmm.dll作为使用其高精度计时功能的可能性。

到目前为止我尝试了什么:

  • 使用while循环,使用秒表计算逻辑执行后所需的剩余延迟,然后调用具有该延迟量的Thread.Sleep;这是非常不可靠的,通常导致更长的延迟,偶尔会导致很长的延迟
  • 使用System.Threading.Timer;回调通常每隔~109 ms进行一次调用
  • 使用System.Timers.Timer,我认为更合适,并将AutoReset设置为true; Elapsed事件每隔~109 ms就会提高一次。
  • 使用高精度计时器,例如可以找到herehere的计时器。然而,这导致(可以预期)非常高的CPU负载,这在我的系统设计中是不合需要的。

到目前为止,最好的选择似乎是使用System.Timers.Timer类。为了纠正上面提到的109毫秒,我将间隔设置为92毫秒(这看起来非常h​​acky ......!)。然后,在事件处理程序中,我使用秒表计算实际经过的时间,然后根据该计算执行我的系统逻辑。

在代码中:

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负载的情况下以稳定的间隔执行重复逻辑执行吗?

1 个答案:

答案 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负载。