我有一个可以托管一个或多个后台线程的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();
}
}
使用一种模式比另一种更有优势吗?在后台线程中设置轮询循环有更好的模式吗?
答案 0 :(得分:3)
我正在尝试寻找一种消耗更少CPU的替代方案。
您是否有任何证据证明它目前实际消耗了大量CPU?除非你有一个很多的线程在相似的时间和相互竞争中醒来,否则我会期望Thread.Sleep
合理有效。
你的递归DoWork
方法远远不够 - 除非它的尾调优化,你最终会爆发堆栈溢出。你为什么不至少循环?你为什么不直接在计时器线程中做实际的工作?
如果你真的想要每个任务一个线程,每秒做一次工作,那么你的第一个代码就可以了(尽管你要确保“看到”keepRunning
的任何新值,如果它只是字段 - 考虑使用Interlocked
)。理想情况下,您根本不应该拥有这些线程 - 只需要有适当的计时器来计划每秒一次的工作,并让线程池处理它。