让工作线程等待任务的最有效的 CPU 方法是什么?
在我当前的 C#/NET 3.5 应用程序中,我有一个任务队列(线程安全),并且有 5 个工作线程,它们必须不断地在队列中查找任务。如果任务可用,任何一个工作人员都会将该任务出队并采取所需的操作。
我的工作线程类如下:
public class WorkerThread
{
//ConcurrentQueue is my implementation of thread safe queue
//Essentially just a wrapper around Queue<T> with synchronization locks
readonly ConcurrentQueue<CheckPrimeTask> mQ;
readonly Thread mWorker;
bool mStop;
public WorkerThread (ConcurrentQueue<CheckPrimeTask> aQ) {
mQ = aQ;
mWorker = new Thread (Work) {IsBackground = true};
mStop = false;
}
private void Work () {
while (!mStop) {
if (mQ.Count == 0) {
Thread.Sleep (0);
continue;
}
var task = mQ.Dequeue ();
//Someone else might have been lucky in stealing
//the task by the time we dequeued it!!
if (task == null)
continue;
task.IsPrime = IsPrime (task.Number);
task.ExecutedBy = Thread.CurrentThread.ManagedThreadId;
//Ask the threadpool to execute the task callback to
//notify completion
ThreadPool.QueueUserWorkItem (task.CallBack, task);
}
}
private bool IsPrime (int number) {
int limit = Convert.ToInt32 (Math.Sqrt (number));
for (int i = 2; i <= limit; i++) {
if (number % i == 0)
return false;
}
return true;
}
public void Start () {
mStop = false;
mWorker.Start ();
}
public void Stop () {
mStop = true;
}
}
问题是当队列为空时,它消耗太多CPU(接近98%)。我尝试使用 AutoResetEvent 来通知工作人员队列已更改。因此,他们实际上等待该信号的设置。它已将 CPU 占用率降低到接近 0%,但我不完全确定这是否是最好的方法。您能否建议一种更好的方法来保持线程空闲而不影响 CPU 使用率?
In my current C#/NET 3.5 application, I have a task queue (thread safe) and I have 5 worker threads that has to constantly look for tasks in the queue. If a task is available, any one worker will dequeue the task and take required action.
My worker thread class is as follows:
public class WorkerThread
{
//ConcurrentQueue is my implementation of thread safe queue
//Essentially just a wrapper around Queue<T> with synchronization locks
readonly ConcurrentQueue<CheckPrimeTask> mQ;
readonly Thread mWorker;
bool mStop;
public WorkerThread (ConcurrentQueue<CheckPrimeTask> aQ) {
mQ = aQ;
mWorker = new Thread (Work) {IsBackground = true};
mStop = false;
}
private void Work () {
while (!mStop) {
if (mQ.Count == 0) {
Thread.Sleep (0);
continue;
}
var task = mQ.Dequeue ();
//Someone else might have been lucky in stealing
//the task by the time we dequeued it!!
if (task == null)
continue;
task.IsPrime = IsPrime (task.Number);
task.ExecutedBy = Thread.CurrentThread.ManagedThreadId;
//Ask the threadpool to execute the task callback to
//notify completion
ThreadPool.QueueUserWorkItem (task.CallBack, task);
}
}
private bool IsPrime (int number) {
int limit = Convert.ToInt32 (Math.Sqrt (number));
for (int i = 2; i <= limit; i++) {
if (number % i == 0)
return false;
}
return true;
}
public void Start () {
mStop = false;
mWorker.Start ();
}
public void Stop () {
mStop = true;
}
}
Problem is that when queue is empty, it consumes too much CPU (nearly 98%). I tried AutoResetEvent to notify the workers that queue has been changed. So they effectively wait for that signal to set. It has braught down the CPU to nearly 0% but I am not entirely sure whether this is the best method. Can you suggest a better method to keep the threads idle without hurting CPU usage?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
查看 BlockingQueue 的实现。如果队列为空,则使用 Monitor.Wait() 使线程进入睡眠状态。添加项目时,它使用 Monitor.Pulse() 唤醒在空队列上休眠的线程。
另一种技术是使用信号量。每次将项目添加到队列时,调用 Release()。当您需要队列中的某个项目时,请调用 WaitOne()。
Check out this implementation of a BlockingQueue. If the queue is empty, it uses Monitor.Wait() to put the thread to sleep. When an item is added, it uses Monitor.Pulse() to wake up a thread that is sleeping on the empty queue.
Another technique is to use a semaphore. Each time you add an item to a queue, call Release(). When you want an item from a queue, call WaitOne().
目前,您的 Work 方法中有
Thread.Sleep(0)
,用于处理没有队列项的情况。将其更改为任何大于 0 的值,您的 CPU 使用率将会下降。尝试10
从...开始You currently have
Thread.Sleep(0)
in your Work method for where there are no queue items. Change it to anything greater than 0 and your CPU use will go down. Try10
to start with...我能想到的有几个选择。
一种方法是在循环期间放置一个小线程睡眠。这基本上会将您的 CPU 使用率降至 0,并且是执行此操作的相当标准的方法。
另一种方法是按照 Mitch Wheat 在评论中的建议使用重置(自动或手动)。
您还可以设计某种 IdleTask,让线程休眠一定时间,如果您的队列为空,则只需处理 IdleTask(这将使线程休眠)。
You have a couple of options that I can think of.
One way is to place a small thread sleep during your loop. This will basically drop your CPU usage to 0 and is fairly standard way of doing this.
Another way is to use a reset (either auto or manual) as suggested by Mitch Wheat in the comments.
You could also devise some kind of IdleTask that has a thread sleep for a certain amount of time and if your queue is empty, just process the IdleTask (which will thread sleep).
如果您的队列是线程安全的,那么您就不需要这样做......
If your Queue is thread safe then you would not need to do this...