C#中线程的动态工作分配

时间:2013-05-02 18:26:35

标签: c# multithreading parallel-processing

我想知道如何设置一个动态分配线程工作的类,最好是在C#中。我已经查看了[this]的光线跟踪器解释,但我甚至没有看到它的外观描述。我不想要一些过于复杂的东西。

我有一组太大的任务,无法均匀分割并发给我的主题。我想动态地将小部分任务分配给每个线程,然后当线程完成时,获取结果并为它们提供更多任务。我知道我多年前做过这样的事情,但是我找不到这些笔记,也没有在谷歌或这里取得过成功。

非常感谢任何帮助。

下面是我对伪代码的看法。它不会看起来很漂亮,只是为了让你知道我在说什么。

TaskList = ArrayList of n tasks
ResultList = ArrayList of thread results
create x threads
integer TasksCompleted
while(TasksCompleted < TaskList.size){
  thread = next available thread in pool
  ResultList.add(thread.results)
  tasksCompleted += thread.numOfTasks
  thread.doWork(Next set of Tasks)
}
clean up threads
processResults(ResultList)

2 个答案:

答案 0 :(得分:1)

如果您使用的是.NET 4.0+,则可以使用Parallel.For方法。它启动尽可能多的线程,以便并行处理循环。好处是它管理线程并为您监视它们。以下是对http://msdn.microsoft.com/en-us/library/dd460713.aspx

的并行方法的介绍

您还应该查看.NET 4.0中引入的任务并行库的其他结构。它有许多非常简洁的多线程助手,使多线程比启动和管理自己的线程容易得多。您可以在此处查看MSDN文档:http://msdn.microsoft.com/en-us/library/dd537609.aspx

答案 1 :(得分:0)

以下是使用BlockingCollection管理简单工作队列的示例。

当一个工作线程完成它的当前项目时,它将从工作队列中删除一个新项目,处理该项目,然后将其添加到输出队列。

一个单独的使用者线程从输出队列中删除已完成的项目并对它们执行某些操作。

最后,我们必须等待所有工作人员完成(Task.WaitAll(workers))才能将输出队列标记为已完成(outputQueue.CompleteAdding())。

此示例仅包含工作项的内容;在实际代码中,您将使用封装工作的对象。

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().run();
        }

        void run()
        {
            int threadCount = 4;
            Task[] workers = new Task[threadCount];

            Task.Factory.StartNew(consumer);

            for (int i = 0; i < threadCount; ++i)
            {
                int workerId = i;
                Task task = new Task(() => worker(workerId));
                workers[i] = task;
                task.Start();
            }

            for (int i = 0; i < 100; ++i)
            {
                Console.WriteLine("Queueing work item {0}", i);
                inputQueue.Add(i);
                Thread.Sleep(50);
            }

            Console.WriteLine("Stopping adding.");
            inputQueue.CompleteAdding();
            Task.WaitAll(workers);
            outputQueue.CompleteAdding();
            Console.WriteLine("Done.");

            Console.ReadLine();
        }

        void worker(int workerId)
        {
            Console.WriteLine("Worker {0} is starting.", workerId);

            foreach (var workItem in inputQueue.GetConsumingEnumerable())
            {
                Console.WriteLine("Worker {0} is processing item {1}", workerId, workItem);
                Thread.Sleep(100);          // Simulate work.
                outputQueue.Add(workItem);  // Output completed item.
            }

            Console.WriteLine("Worker {0} is stopping.", workerId);
        }

        void consumer()
        {
            Console.WriteLine("Consumer is starting.");

            foreach (var workItem in outputQueue.GetConsumingEnumerable())
            {
                Console.WriteLine("Consumer is using item {0}", workItem);
                Thread.Sleep(25);
            }

            Console.WriteLine("Consumer is finished.");
        }

        BlockingCollection<int> inputQueue = new BlockingCollection<int>();
        BlockingCollection<int> outputQueue = new BlockingCollection<int>();
    }
}

Plinq和数据流

You should also look into Plinq,以及 - 如果您可以使用.Net 4.5 - 还Dataflow (Task Parallel Library)