Thread.Sleep()与Monitor.Wait / Monitor.Pulse

时间:2012-10-22 22:19:25

标签: .net multithreading

我有一个可以托管一个或多个后台线程的Windows服务。每个后台线程都会启动一个轮询循环来检查工作。我一直在使用以下模式来实现循环:

new Thread(DoWork).Start();

private void DoWork()
{
    while(keepRunning)
    {
        Console.WriteLine(DateTime.Now);
        Thread.Sleep(1000);
    }
}

我正在尝试寻找一种消耗更少CPU的替代方案。我已经能够使用带有递归方法的Timer实现轮询循环:

var timer = new Timer(WakeUp, null, Timeout.Infinite, 1000)
timer.Change(0, 1000);

private void WakeUp(object state)
{
    lock (locker)
        Monitor.Pulse(locker);
}

private void DoWork()
{
    lock (locker)
    {
        if (!keepRunning) return;
        Console.WriteLine(DateTime.Now);
        Monitor.Wait(locker);
        DoWork();
    }
}

使用一种模式比另一种更有优势吗?在后台线程中设置轮询循环有更好的模式吗?

1 个答案:

答案 0 :(得分:3)

  

我正在尝试寻找一种消耗更少CPU的替代方案。

您是否有任何证据证明它目前实际消耗了大量CPU?除非你有一个很多的线程在相似的时间和相互竞争中醒来,否则我会期望Thread.Sleep合理有效。

你的递归DoWork方法远远不够 - 除非它的尾调优化,你最终会爆发堆栈溢出。你为什么不至少循环?你为什么不直接在计时器线程中做实际的工作?

如果你真的想要每个任务一个线程,每秒做一次工作,那么你的第一个代码就可以了(尽管你要确保“看到”keepRunning的任何新值,如果它只是字段 - 考​​虑使用Interlocked)。理想情况下,您根本不应该拥有这些线程 - 只需要有适当的计时器来计划每秒一次的工作,并让线程池处理它。