Как правильно ответили другие, метод 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()
в ваш запрос, когдаиспользуя любой из вышеперечисленных методов расширения, он в любом случае вызывается внутренне.
Я обнаружил, что эти методы полезны при обработке элементов, которые имеют крупнозернистое значение.Это может быть полезно, например, для обработки записей, начиная с самой старой и работая с самой новой.Во многих случаях точный порядок записей не требуется - поскольку старые записи обычно обрабатываются раньше новых записей.Аналогичным образом, записи, имеющие низкий / средний / высокий приоритетный уровень, могут быть обработаны таким образом, что записи с высоким приоритетом будут обрабатываться перед записями с более низким приоритетом для большинства случаев, причем крайние случаи не сильно отстают.