Parallel.ForEach 会按照 MaxDegreeOfParallelism=1 的顺序进行处理吗?

Posted

技术标签:

【中文标题】Parallel.ForEach 会按照 MaxDegreeOfParallelism=1 的顺序进行处理吗?【英文标题】:Will Parallel.ForEach process in order with MaxDegreeOfParallelism=1? 【发布时间】:2017-08-06 07:08:02 【问题描述】:

Parallel.ForEach()MaxDegreeOfParallelism==1 是否保证按顺序处理输入可枚举?

如果答案是“否”,有没有办法强制执行这种行为?

【问题讨论】:

我能问一下你为什么想知道这个吗?只是学术好奇心,还是您遇到了某种现实问题? @mituw16:我在链接的 MSDN 文章中找不到任何提示。进行一些测试也不能保证“是”。 这样的问题取决于实现细节,如果 msdn 没有说明,将来可以更改。你需要按顺序运行吗?然后使用Queue<> 如果您的测试代码需要按顺序处理实际情况下不按顺序排列的内容,那么您的测试就有缺陷。重写它以便验证结果不依赖于这个假设,或者重写被测代码以在 MaxDegreeOfParallelism 为 1 时产生显式异常,这样您就可以确保它在所有情况下的行为一致。显然,第一个选项更可取。 @l33t - 查看源代码或运行测试不会告诉您有关未来实现的任何信息。您需要文档中的 explicit 语句。 【参考方案1】:

首先,Microsoft's official documentation on parallel programming 声明执行顺序无法保证是正确的。

Parallel.ForEach 方法不保证执行顺序。与顺序 ForEach 循环不同,传入的值并不总是按顺序处理。

最好使用Parallel.ForEach,因为公共 API 的设计目的是:以并行方式处理项目。如果您需要按顺序处理项目,最好使用常规的foreach 循环。意图比使用MaxDegreeOfParallelism = 1 更清晰。

话虽如此,出于好奇,我查看了 .NET 4.7.1 的源代码。简短的回答是是的,如果MaxDegreeOfParallelism = 1,项目将按顺序处理。但是,您不应该在未来的实现中依赖它,因为它可能并不总是这样。

    看一下Parallel.ForEach,然后继续看下去,你最终会看到要迭代的集合是分区的(这个过程有点不同,不管是TSource[]List<TSource>,或IEnumerable<TSource>

    Task.SavedStateForNextReplicaTask.SavedStateFromPreviousReplicaParallelForReplicaTask 中被覆盖,以便在并行运行的任务之间传达状态。在这种情况下,它们用于传达任务应该迭代哪个分区。

    最后,我们来看看Task.ExecuteSelfReplicatingParallelForReplicatingTask 根据指定的并行度以及任务调度程序的 MaximumConcurrencyLevel 覆盖 ShouldReplicate。所以,MaxDegreeOfParallelism = 1 只会创建一个子任务。因此,此任务将仅在创建的单个分区上运行。

所以,为了回答您的问题:在撰写本文时,Parallel.ForEachMaxDegreeOfParallism = 1 将枚举集合 from beginning to end 为 TSource[],from beginning to end 为 IList<TSource>,use GetEnumerator 为 @ 987654349@,路径略有不同,具体取决于 IEnumerable<TSource> 是否可以转换为 OrderablePartitioner<TSource>。这三个路径在Parallel.ForEachWorker中确定。

我强烈建议您自行浏览源代码以亲自查看。

我希望这能够回答你的问题,但记住这一点非常重要:不要依赖这个。这种实现很有可能在未来发生变化。

【讨论】:

【参考方案2】:

来自 MSDN:

Parallel.ForEach 方法不保证执行顺序。与顺序 ForEach 循环不同,传入的值并不总是按顺序处理。

https://msdn.microsoft.com/library/ff963552.aspx

【讨论】:

以上是关于Parallel.ForEach 会按照 MaxDegreeOfParallelism=1 的顺序进行处理吗?的主要内容,如果未能解决你的问题,请参考以下文章

C#并发实战Parallel.ForEach使用

计算 Parallel.ForEach 使用的线程数

Parallel.ForEach 比 ForEach 慢

打破parallel.foreach?

何时使用 Parallel.ForEach,何时使用 PLINQ

Parallel.ForEach 内存不足异常