Thread.Sleep()的心跳实现

时间:2012-02-22 17:26:46

标签: c# sleep heartbeat

在我的应用程序中,我有一个“心跳”功能,目前在长时间运行的线程中以下列方式实现(伪代码):

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

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

现在,当我的应用程序经历一些密集的CPU时间(几分钟的繁重计算,其中CPU占用率> 90%)时,心跳加速,即使smallInterval<< heartbeatInterval。

要处理一些数字:heartbeatInterval为60秒,lastHeartbeat为0.1秒,报告的延迟最长为15秒。因此,根据我的理解,这意味着当CPU非常繁忙时,睡眠(10)可以像睡眠(15000)一样持续。

我已经尝试将线程优先级设置为AboveNormal - 如何改进我的设计以避免此类问题?

3 个答案:

答案 0 :(得分:4)

你有什么理由不能使用Timer吗?您可以使用三种类型,我通常会选择System.Timers.Timer。以下文章讨论了差异:

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

本质上,计时器允许您设置定期间隔的计时器,并在该周期过去时触发事件。然后,您可以使用调用sendHeartbeat()的代理订阅该事件。

定时器应该更好地为您服务,因为它们不会像睡眠线程一样受到CPU负载的影响。它的优点是在代码方面有点整洁(定时器设置非常简单和可读)并且你不会有闲置的线程。

答案 1 :(得分:3)

您似乎正在尝试重新发明其中一个计时器类。

例如,如何使用System.Timers.Timer

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

这里的一个问题可能是,在CPU处于负载状态时,您的线程调度的频率。您的计时器实现本质上是单线程和块。移动到其中一个框架计时器应该缓解这个问题(以上面的计时器为例)在线程池线程上引发了已发生的事件,其中有很多。

答案 2 :(得分:2)

不幸的是,Windows不是实时操作系统,因此很少有关于何时执行线程的保证。 Thread.Sleep ()仅调度下一次唤醒线程的最早时间,由空闲时间片唤醒线程由操作系统决定。可能没有记录唤醒睡眠线程的确切标准,因此Window的内核团队可以根据需要更改实现。

我不确定Timer对象是否会解决此问题,因为在计时器到期后仍需要激活心跳线程。

一种解决方案是提升心跳线程的优先级,以便更频繁地执行。

但是,心跳通常用于确定子系统是否卡在无限循环中,因此它们通常是低优先级的。当您拥有CPU密集型部分时,请在关键点执行Thread.Sleep (0)以允许较低优先级的线程执行。