正如其他人正确回答的那样,ForAll 方法永远不能保证以任何特定顺序对可枚举元素执行操作,并且会默默地忽略 AsOrdered() 方法调用。
为了让读者有正当理由以接近原始顺序的方式对可枚举元素执行操作(在并行处理上下文中尽可能合理),下面的扩展方法可能会有所帮助。
public static void ForAllInApproximateOrder<TSource>(this ParallelQuery<TSource> source, Action<TSource> action) {
Partitioner.Create( source )
.AsParallel()
.AsOrdered()
.ForAll( e => action( e ) );
}
然后可以按如下方式使用:
orderedElements.AsParallel()
.ForAllInApproximateOrder( e => DoSomething( e ) );
需要注意的是,上述扩展方法使用 PLINQ ForAll 而不是 Parallel.ForEach,因此继承了 PLINQ 内部使用的线程模型(这与 Parallel.ForEach 使用的不同——在默认情况下不那么激进)我的经验)。下面是使用Parallel.ForEach的类似扩展方法。
public static void ForEachInApproximateOrder<TSource>(this ParallelQuery<TSource> source, Action<TSource> action) {
source = Partitioner.Create( source )
.AsParallel()
.AsOrdered();
Parallel.ForEach( source , e => action( e ) );
}
然后可以按如下方式使用:
orderedElements.AsParallel()
.ForEachInApproximateOrder( e => DoSomething( e ) );
使用上述任一扩展方法时,无需将AsOrdered() 链接到您的查询,无论如何它都会在内部调用。
我发现这些方法在处理具有粗粒度意义的元素时很有用。例如,它可以用于处理从最旧开始并朝着最新的记录。在许多情况下,不需要记录的确切顺序 - 只要较旧的记录通常在较新的记录之前得到处理。同样,可以处理具有低/中/高优先级的记录,这样在大多数情况下,高优先级记录将在低优先级记录之前处理,边缘情况紧随其后。