让工作线程等待任务的最有效的 CPU 方法是什么?

发布于 2024-08-17 15:19:50 字数 1807 浏览 5 评论 0原文

在我当前的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

七七 2024-08-24 15:19:50

查看 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().

最笨的告白 2024-08-24 15:19:50

目前,您的 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. Try 10 to start with...

我很OK 2024-08-24 15:19:50

我能想到的有几个选择。

一种方法是在循环期间放置一个小线程睡眠。这基本上会将您的 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).

剑心龙吟 2024-08-24 15:19:50

如果您的队列是线程安全的,那么您就不需要这样做......

    //Someone else might have been lucky in stealing 
    //the task by the time we dequeued it!! 
    if (task == null)  
        continue; 

If your Queue is thread safe then you would not need to do this...

    //Someone else might have been lucky in stealing 
    //the task by the time we dequeued it!! 
    if (task == null)  
        continue; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文