使用 MaxDegreeOfParallelism==1
的 Parallel.ForEach()
是否保证按顺序处理可枚举的输入?
如果答案是“否”,是否有办法强制执行此行为?
最佳答案
首先,Microsoft's official documentation on parallel programming 是正确的声明执行顺序无法保证。
The Parallel.ForEach method does not guarantee the order of execution. Unlike a sequential ForEach loop, the incoming values aren't always processed in order.
最好使用Parallel.ForEach
因为公共(public) API 的设计目的是:以并行方式处理项目。如果您需要按顺序处理项目,最好使用常规 foreach
环形。意图比使用 MaxDegreeOfParallelism = 1
更清晰.
话虽如此,出于好奇,我查看了 .NET 4.7.1 的源代码。简短的回答是是的,如果MaxDegreeOfParallelism = 1
,项目将按顺序处理。 强>。但是,您不应该在未来的实现中依赖它,因为它可能并不总是这样。
查看
Parallel.ForEach
并按照它完成,您最终会看到要迭代的集合已分区(此过程略有不同,无论是TSource[]
、List<TSource>
还是IEnumerable<TSource>
。Task.SavedStateForNextReplica
和Task.SavedStateFromPreviousReplica
在ParallelForReplicaTask
中被覆盖为了在并行运行的任务之间传递状态。在这种情况下,它们用于传达任务应该遍历哪个分区。最后,我们来看看
Task.ExecuteSelfReplicating
.ParallelForReplicatingTask
覆盖ShouldReplicate
基于指定的并行度以及任务调度程序的MaximumConcurrencyLevel
.所以,这与MaxDegreeOfParallelism = 1
只会创建一个子任务。因此,此任务将仅对创建的单个分区进行操作。
因此,回答您的问题:截至撰写本文时,Parallel.ForEach
与 MaxDegreeOfParallism = 1
将枚举集合 from beginning to end对于 TSource[]
, from beginning to end对于 IList<TSource>
, 和 use GetEnumerator
对于 IEnumerable<TSource>
,路径略有不同,具体取决于 IEnumerable<TSource>
是否可以转换为 OrderablePartitioner<TSource>
或不。这三个路径在 Parallel.ForEachWorker
中确定.
我强烈建议您自己浏览源代码,亲自看看。
我希望这能够回答您的问题,但记住这一点非常重要:不要依赖它。这种实现很可能在未来发生变化。
关于c# - Parallel.ForEach 会按照 MaxDegreeOfParallelism=1 的顺序进行处理吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42811544/