正如其他人正确回答的那样,
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()
链接到您的查询中,因为它会在内部自动调用。
我发现这些方法对于处理具有粗粒度意义的元素非常有用。例如,按照最旧的记录开始处理并向最新的记录进行处理可能是有用的。在许多情况下,并不需要记录的确切顺序——只要较旧的记录通常在较新的记录之前处理即可。同样,可以处理具有低/中/高优先级级别的记录,以便在大多数情况下先处理高优先级记录,而边缘情况稍微滞后。