简体   繁体   English

Thread.Sleep()的心跳实现

[英]Heartbeat implementation with Thread.Sleep()

in my application I have an "heartbeat" functionality that is currently implemented in a long running thread in the following way (pseudocode): 在我的应用程序中,我有一个“心跳”功能,目前在长时间运行的线程中以下列方式实现(伪代码):

while (shouldBeRunning)
{
    Thread.Sleep(smallInterval);

    if (DateTime.UtcNow - lastHeartbeat > heartbeatInterval)
    {
        sendHeartbeat();
        lastHeartbeat = DateTime.UtcNow;
    } 
}

Now, it happens that when my application is going through some intensive CPU time (several minutes of heavy calculations in which the CPU is > 90% occupied), the heartbeats get delayed, even if smallInterval << heartbeatInterval. 现在,当我的应用程序经历一些密集的CPU时间(几分钟的繁重计算,其中CPU占用率> 90%)时,即使smallInterval << heartbeatInterval,心跳也会延迟。

To crunch some numbers: heartbeatInterval is 60 seconds, lastHeartbeat is 0.1 seconds and the reported delay can be up to 15s. 要收紧一些数字:heartbeatInterval是60秒,lastHeartbeat是0.1秒,报告的延迟可以达到15秒。 So, in my understanding, that means that a Sleep(10) can last like a Sleep(15000) when the CPU is very busy. 因此,根据我的理解,这意味着当CPU非常繁忙时,睡眠(10)可以像睡眠(15000)一样持续。

I have already tried setting the thread priority as AboveNormal - how can I improve my design to avoid such problems? 我已经尝试将线程优先级设置为AboveNormal - 如何改进我的设计以避免此类问题?

Is there any reason you can't use a Timer for this? 你有什么理由不能使用Timer吗? There are three sorts you can use and I usually go for System.Timers.Timer . 您可以使用三种类型,我通常使用System.Timers.Timer The following article discusses the differences though: 以下文章讨论了差异:

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

Essentially timers will allow you to set up a timer with a periodic interval and fire an event whenever that period ticks past. 本质上,计时器将允许您设置定期间隔的计时器,并在该周期过去时触发事件。 You can then subscribe to the event with a delegate that calls sendHeartbeat() . 然后,您可以使用调用sendHeartbeat()的委托订阅该事件。

Timers should serve you better since they won't be affected by the CPU load in the same way as your sleeping thread. 定时器应该更好地为您服务,因为它们不会像睡眠线程一样受到CPU负载的影响。 It has the advantage of being a bit neater in terms of code (the timer set up is very simple and readable) and you won't have a spare thread lying around. 它具有在代码方面更整洁的优点(定时器设置非常简单和可读)并且您不会有闲置的线程。

You seem to be trying to reinvent one of the timer classes. 您似乎正在尝试重新发明其中一个计时器类。

How about using System.Timers.Timer for example? 例如,如何使用System.Timers.Timer

var timer = new System.Timers.Timer(smallInterval);
timer.Elapsed += (s, a) => sendHeartbeat;
timer.Enabled = true;

One of the issues here may be, at a guess, how often your thread gets scheduled when the CPU is under load. 其中一个问题可能是,在CPU处于负载状态时,您的线程调度的频率。 Your timer implementation is inherently single threaded and blocks. 您的计时器实现本质上是单线程和块。 A move to one of the framework timers should alleviate this as (taking the above timer as an example) the elapsed event is raised on a thread pool thread, of which there are many. 移动到其中一个框架计时器应该缓解这一点(以上面的计时器为例)在线程池线程上引发了已经过去的事件,其中有很多。

Unfortunately, Windows is not a Real Time OS and so there are few guarantees about when threads are executed. 不幸的是,Windows不是实时操作系统,因此几乎没有关于何时执行线程的保证。 The Thread.Sleep () only schedules the earliest time when the thread should be woken up next, it is up to the OS to wake up the thread when there's a free time slice. Thread.Sleep ()仅调度线程应该在下一次唤醒时的最早时间,当有空闲时间片时,由OS来唤醒线程。 The exact criteria for waking up a sleeping thread is probably not documented so that the Window's kernel team can change the implementation as they see fit. 可能没有记录唤醒睡眠线程的确切标准,以便Window的内核团队可以根据需要更改实现。

I'm not sure that Timer objects will solve this as the heartbeat thread still needs to be activated after the timer has expired. 我不确定Timer对象是否会解决此问题,因为在计时器到期后仍需要激活心跳线程。

One solution is to elevate the priority of the heartbeat thread so that it gets a chance of executing more often. 一种解决方案是提升心跳线程的优先级,以便它有更频繁地执行的机会。

However, heartbeats are usually used to determine if a sub-system has got stuck in an infinite loop for example, so they are generally low priority. 但是,心跳通常用于确定子系统是否卡在无限循环中,因此它们通常是低优先级的。 When you have a CPU intensive section, do a Thread.Sleep (0) at key points to allow lower priority threads a chance to execute. 当您拥有CPU密集型部分时,请在关键点执行Thread.Sleep (0)以允许较低优先级的线程执行。

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

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