为了我正在处理的一个项目,我需要每秒执行一些逻辑(几乎)精确地10次。我知道非实时操作系统的限制,偶尔的10-20%的余量是可以接受的;也就是说,在周期之间偶尔出现长达120毫秒的延迟是可以接受的。然而,重要的是我能够绝对保证逻辑执行的周期性,并且不会发生超出上述范围的延迟。这似乎在C#中很难实现。
我的情况如下:应用程序启动后的一段时间内,触发一个事件,该事件将开始逻辑执行周期。当该周期运行时,程序还处理其他任务,例如通信、日志记录等。 我需要能够在Windows上使用.NET和在Linux上使用Mono运行程序。这排除了导入winmm.dll作为使用其高精度计时函数的可能性。
我到目前为止尝试过的方法:
- 使用while循环,使用Stopwatch计算逻辑执行后所需的剩余延迟时间,然后调用Thread.Sleep以该延迟时间为参数;这种方法非常不可靠,通常会导致更长的延迟,并偶尔导致非常长的延迟。 - 使用System.Threading.Timer;回调通常每109ms调用一次。 - 使用System.Timers.Timer,我认为这更合适,并将AutoReset设置为true;Elapsed事件每109ms被触发一次。 - 使用高精度计时器,例如可以在这里或这里找到的计时器。然而,这会导致非常高的CPU负载,这不符合我的系统设计要求。
到目前为止,最好的选择似乎是使用System.Timers.Timer类。为了纠正上述109ms,我将间隔设置为92ms(这似乎非常hacky...!)。然后,在事件处理程序中,我使用Stopwatch计算实际经过的时间,然后根据该计算执行我的系统逻辑。
代码如下:
我的情况如下:应用程序启动后的一段时间内,触发一个事件,该事件将开始逻辑执行周期。当该周期运行时,程序还处理其他任务,例如通信、日志记录等。 我需要能够在Windows上使用.NET和在Linux上使用Mono运行程序。这排除了导入winmm.dll作为使用其高精度计时函数的可能性。
我到目前为止尝试过的方法:
- 使用while循环,使用Stopwatch计算逻辑执行后所需的剩余延迟时间,然后调用Thread.Sleep以该延迟时间为参数;这种方法非常不可靠,通常会导致更长的延迟,并偶尔导致非常长的延迟。 - 使用System.Threading.Timer;回调通常每109ms调用一次。 - 使用System.Timers.Timer,我认为这更合适,并将AutoReset设置为true;Elapsed事件每109ms被触发一次。 - 使用高精度计时器,例如可以在这里或这里找到的计时器。然而,这会导致非常高的CPU负载,这不符合我的系统设计要求。
到目前为止,最好的选择似乎是使用System.Timers.Timer类。为了纠正上述109ms,我将间隔设置为92ms(这似乎非常hacky...!)。然后,在事件处理程序中,我使用Stopwatch计算实际经过的时间,然后根据该计算执行我的系统逻辑。
代码如下:
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毫秒(在Mono上)。这意味着我会错过一个或多个逻辑执行周期,可能会产生潜在的危害。
是否有更好的方法来处理这个问题?或者这个问题是由操作系统工作方式固有的,并且没有更可靠的方法来进行重复逻辑执行并保持稳定的时间间隔而不会导致高CPU负载?