MaxDegreeOfParallelism=1 时 Parallel.ForEach 会按顺序处理吗?
Will Parallel.ForEach process in order with MaxDegreeOfParallelism=1?
Parallel.ForEach()
和 MaxDegreeOfParallelism==1
是否保证按顺序处理输入可枚举?
如果答案是 "no",有没有办法强制执行此行为?
来自 MSDN:
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.
首先,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
根据指定的并行度以及任务调度程序的 MaximumConcurrencyLevel
覆盖 ShouldReplicate
。因此,使用 MaxDegreeOfParallelism = 1
只会创建一个子任务。因此,此任务将仅对创建的单个分区进行操作。
因此,回答您的问题:在撰写本文时,Parallel.ForEach
和 MaxDegreeOfParallism = 1
将枚举集合 from beginning to end for a TSource[]
, from beginning to end for an IList<TSource>
, and use GetEnumerator
for an IEnumerable<TSource>
, with slightly different paths depending on if the IEnumerable<TSource>
can be cast to an OrderablePartitioner<TSource>
or not. These three paths are determined in Parallel.ForEachWorker
.
我强烈建议您自己浏览源代码以亲自查看。
我希望这能够回答你的问题,但记住这一点非常重要:不要依赖这个。这种实现很可能在未来发生变化。
答案是否定的,但您可以使用 AsOrdered() 强制执行此行为,如下所示。
using System;
using System.Linq;
using System.Threading.Tasks;
var items = Enumerable.Range(0, 1000).ToArray();
Parallel.ForEach(items.AsParallel().AsOrdered(),
new ParallelOptions { MaxDegreeOfParallelism = 1 },
Console.WriteLine);
SharpLab 样本here
显然,如果您增加 MaxDegreeOfParallelism
,每个并行任务将处理其 chunk(或 chunks)项 - 在它们在原始 ordered 列表中出现的顺序。
Parallel.ForEach()
和 MaxDegreeOfParallelism==1
是否保证按顺序处理输入可枚举?
如果答案是 "no",有没有办法强制执行此行为?
来自 MSDN:
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.
首先,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
根据指定的并行度以及任务调度程序的MaximumConcurrencyLevel
覆盖ShouldReplicate
。因此,使用MaxDegreeOfParallelism = 1
只会创建一个子任务。因此,此任务将仅对创建的单个分区进行操作。
因此,回答您的问题:在撰写本文时,Parallel.ForEach
和 MaxDegreeOfParallism = 1
将枚举集合 from beginning to end for a TSource[]
, from beginning to end for an IList<TSource>
, and use GetEnumerator
for an IEnumerable<TSource>
, with slightly different paths depending on if the IEnumerable<TSource>
can be cast to an OrderablePartitioner<TSource>
or not. These three paths are determined in Parallel.ForEachWorker
.
我强烈建议您自己浏览源代码以亲自查看。
我希望这能够回答你的问题,但记住这一点非常重要:不要依赖这个。这种实现很可能在未来发生变化。
答案是否定的,但您可以使用 AsOrdered() 强制执行此行为,如下所示。
using System;
using System.Linq;
using System.Threading.Tasks;
var items = Enumerable.Range(0, 1000).ToArray();
Parallel.ForEach(items.AsParallel().AsOrdered(),
new ParallelOptions { MaxDegreeOfParallelism = 1 },
Console.WriteLine);
SharpLab 样本here
显然,如果您增加 MaxDegreeOfParallelism
,每个并行任务将处理其 chunk(或 chunks)项 - 在它们在原始 ordered 列表中出现的顺序。