任务调度程序中的手动线程与Parallel.Foreach

时间:2013-11-19 23:40:35

标签: c# task-parallel-library parallel.foreach

我有一个Windows服务来处理用户创建的任务。此服务在具有4个核心的服务器上运行。这些任务主要涉及繁重的数据库工作(例如生成报告)。服务器还运行了一些其他服务,所以我不想激活太多的线程(假设最多4个)。

如果我使用BlockingCollection<MyCustomTask>,最好创建4个Thread对象并使用这些对象来使用BlockingCollection<MyCustomTask>,还是应该使用Parallel.Foreach来完成此操作?

我正在查看包含StaTaskScheduler的ParallelExtensionsExtras,它使用前者,就像这样(为了清晰起见,稍微修改了代码):

var threads = Enumerable.Range(0, numberOfThreads).Select(i =>
                       {
                           var thread = new Thread(() =>
                           {
                               // Continually get the next task and try to execute it.
                               // This will continue until the scheduler is disposed and no more tasks remain.
                               foreach (var t in _tasks.GetConsumingEnumerable())
                               {
                                   TryExecuteTask(t);
                               }
                           });
                           thread.IsBackground = true;
                           thread.SetApartmentState(ApartmentState.STA);
                           return thread;
                       }).ToList();

            // Start all of the threads
            threads.ForEach(t => t.Start());

但是,同一个ParallelExtensionsExtras中还有一个BlockingCollectionPartitioner可以在Parallel.Foreach上使用BlockingCollection<Task>,如下所示:

 var blockingCollection = new BlockingCollection<MyCustomTask>();
        Parallel.ForEach(blockingCollection.GetConsumingEnumerable(), task =>
        {
            task.DoSomething();
        });

我理解后者利用ThreadPool。在这种情况下使用Parallel.ForEach会有什么好处吗?

1 个答案:

答案 0 :(得分:3)

如果您的代码中的Task类与System.Threading.Tasks.Task无关,那么这个答案是相关的。

作为一个简单的规则,使用Parallel.ForEach来运行最终结束的任务。就像执行一些与其他工作并行的工作

在应用程序的整个生命周期中运行例程时使用线程。

因此,在您的情况下,您应该使用Threads方法。