【问题标题】:Manual threads vs Parallel.Foreach in task scheduler任务调度程序中的手动线程与 Parallel.Foreach
【发布时间】:2013-11-19 23:40:34
【问题描述】:

我有一个处理用户创建的任务的 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 可以在 BlockingCollection<Task> 上使用 Parallel.Foreach,如下所示:

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

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

【问题讨论】:

  • 你写的没有多大意义。 Tasks 和 Parallel.ForEach 基于线程。因此,您运行线程来运行任务(例如运行更多线程)。此解决方案不会帮助您提高性能。
  • Task 是一个定制的类(即不是 System.Threading.Tasks.Task)。我已编辑问题以使其更清楚。
  • 如果 TPL 确定一组任务通过并行运行将获得很少或没有任何好处,它将选择按顺序执行它们而不是并行执行。是的,它利用 ThreadPool 并管理并发您的代表
  • 要记住的一点是,如果阻塞集合花费大量时间为空,Parallel.ForEach 可能会启动过多的线程池线程(这在并行编程模式中进行了讨论,第 88 页)。您说您只希望 4 个线程处理您的“任务”,因此请务必通过 ParallelOptions.MaxDegreeOfParallelism 限制并行度。

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


【解决方案1】:

如果代码中的 Task 类与 System.Threading.Tasks.Task 无关,则此答案是相关的。

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

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

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

【讨论】:

    猜你喜欢
    • 2021-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    相关资源
    最近更新 更多