Is Parallel.ForEach()
with MaxDegreeOfParallelism==1
保证按顺序处理可枚举的输入?
如果答案是“否”,有没有办法强制执行这种行为?
首先,以下说法正确的是微软关于并行编程的官方文档 https://msdn.microsoft.com/library/ff963552.aspx指出不保证执行顺序.
Parallel.ForEach 方法不保证执行顺序。与顺序 ForEach 循环不同,传入值并不总是按顺序处理。
最好使用Parallel.ForEach
公共 API 的设计如下:以并行方式处理项目。如果您需要按顺序处理项目,那么最好使用常规方法foreach
环形。意图比使用更明确MaxDegreeOfParallelism = 1
.
话虽如此,出于好奇,我查看了 .NET 4.7.1 的源代码。简短的答案是是的,如果出现以下情况,将按顺序处理这些项目MaxDegreeOfParallelism = 1
。但是,您不应该在未来的实现中依赖于此,因为它可能并不总是这样。
看看Parallel.ForEach https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Parallel.cs,d64f86dd50921f5b继续下去,您最终会看到要迭代的集合已分区(无论它是一个集合,这个过程都略有不同)TSource[]
, List<TSource>
, or an IEnumerable<TSource>
.
Task.SavedStateForNextReplica
and Task.SavedStateFromPreviousReplica
被覆盖在ParallelForReplicaTask
为了在并行运行的任务之间传达状态。在这种情况下,它们用于传达任务应该迭代的分区。
最后我们来看看Task.ExecuteSelfReplicating https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,b10f1afbb0308278. ParallelForReplicatingTask
覆盖ShouldReplicate
基于指定的并行度以及任务调度程序的MaximumConcurrencyLevel
。所以,这与MaxDegreeOfParallelism = 1
只会创建一个子任务。因此,此任务将仅对创建的单个分区进行操作。
所以,回答你的问题:截至撰写本文时,Parallel.ForEach
with MaxDegreeOfParallism = 1
将枚举集合从开始到结束 https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Parallel.cs,6cd8a40307748c3d for a TSource[]
, 从开始到结束 https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Parallel.cs,9e0ecf73a270a93a for an IList<TSource>
, and use GetEnumerator https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Parallel.cs,38a83efeaf70c495 for an IEnumerable<TSource>
,路径略有不同,具体取决于是否IEnumerable<TSource>
可以转换为OrderablePartitioner<TSource>
或不。这三个路径由Parallel.ForEachWorker https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Parallel.cs,ecf3d8a35545d82b.
我强烈建议您自行浏览源代码以亲自查看。
我希望这能够回答您的问题,但记住这一点非常重要:不要依赖这个。这种实现方式很可能在未来发生改变。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)