c# - 如何提高 Parallel.ForEach 的吞吐量

标签 c# .net-4.0 parallel.foreach

我尝试通过并行执行来优化代码,但有时只有一个线程承担所有繁重的负载。下面的例子展示了 40 个任务应该如何在最多 4 个线程中执行,前十个任务比其他的更耗时。

Parallel.ForEach 似乎将数组分成 4 个部分,并让一个线程处理每个部分。所以整个执行大约需要10秒。它应该能够在最多 3.3 秒内完成!

有没有一种方法可以一直使用所有线程,因为在我的实际问题中不知道哪些任务是耗时的?

var array = System.Linq.Enumerable.Range(0, 40).ToArray();

System.Threading.Tasks.Parallel.ForEach(array, new System.Threading.Tasks.ParallelOptions() { MaxDegreeOfParallelism = 4, },
     i =>
     {
         Console.WriteLine("Running index {0,3} : {1}", i, DateTime.Now.ToString("HH:mm:ss.fff"));
         System.Threading.Thread.Sleep(i < 10 ? 1000 : 10);
     });

最佳答案

使用 Parallel.ForEach 可能,但您需要使用自定义分区器(或找到第 3 方分区器),它能够根据您的需求更明智地对元素进行分区特定项目。 (或者只使用小得多的批处理。)

这也假设您事先并不知道哪些项目会很快,哪些项目会很慢;如果这样做,您可以在调用 ForEach 之前自行重新订购这些元素,这样昂贵的元素就可以分散开来。根据具体情况,这可能足够也可能不够。

一般来说,我更喜欢通过简单地让一个生产者和多个消费者来解决这些问题,每个消费者一次处理一个项目,而不是分批处理。 BlockingCollection 类使这些情况变得相当简单。只需将所有项目添加到集合中,创建 N 个任务/线程/等,每个任务/线程/等等,每个任务都抓取一个项目并处理它,直到没有更多项目为止。它不会为您提供 Parallel.ForEach 为您提供的动态添加/删除线程,但这在您的情况下似乎不是问题。

关于c# - 如何提高 Parallel.ForEach 的吞吐量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20076271/

相关文章:

.net-4.0 - .Net Framework 4 扩展是什么?

c# - parallel.foreach 有效,但为什么呢?

c# - VB6 到 C# InsTR 函数转换问题

c# - MonoTouch - UIView.Animate 完成回调未在按钮 touchUpInside 委托(delegate)内调用

.net - 为什么第一个 WCF 客户端调用很慢?

c# - 如何在不知道 T 是什么的情况下将 T 类型的项目添加到 List<T>?

c# - 从 Parallel.ForEach 抛出时未处理的 OperationCanceledException

.net - Parallel.For 多久调用一次 localInit?

c# - 从 32 位整数到 4 个字符的转换

c# - 使用 Azure Active Directory 进行 Azure Function 身份验证