Заказанный PLINQ ForAll
документация msdn о сохранение заказа в PLINQ говорится о ForAll()
.
- результат, когда исходная последовательность приказал: выполняет недетерминированно параллельно
- результат, когда исходная последовательность ненумерованный: выполняет недетерминированно параллельно
означает ли это, что упорядоченное выполнение ForAll
метод никогда не гарантируется?
Я не использовал PLINQ раньше, но следующее код обзор вопрос казалось подходящим использованием для этого. В конце ответа я пишу:--9-->
Events.AsParallel().AsOrdered().ForAll( eventItem =>
{
...
} );
после прочтения документации я верю AsOrdered()
ничего не изменит?
я также подозреваю, что предыдущий запрос не может заменить простой for
петля, где порядок важен?
вероятно, параллельные вызовы StringBuilder
также будет происходить, в результате неправильный выход?
4 ответов
сохранение заказа обычно применяется только к результаты - т. е. вход может быть обработки в любом порядке, но вернулся в исходном порядке.
As ForAll
ничего не возвращает, на самом деле это не имеет никакого эффекта, о котором я знаю.
единственный способ сделать заказ применить к обработка было бы закончить деталь 0 перед обрабатывать деталь 1, перед обрабатывать деталь 2 etc... в какой момент у вас нет параллелизма.
как справедливо ответили другие,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
и поэтому наследует модель резьбы, используемую interally 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()
к вашему запросу при использовании любого из вышеуказанных методов расширения он все равно вызывается внутренне.
Я нашел эти методы полезными при обработке элементов, которые имеют крупнозернистое значение. Может быть полезно, например, обрабатывать записи, начиная с самых старых и работая в направлении новейших. Во многих случаях точный порядок записей не требуется - поскольку старые записи обычно обрабатываются до новых записей. Аналогично, записи низкоприоритетные/med / high priority уровни могут быть обработаны таким образом, что записи с высоким приоритетом будут обработаны до записей с более низким приоритетом для большинства случаев, с крайними случаями не далеко позади.
AsOrdered()
ничего не изменит - если вы хотите обеспечить порядок в результате параллельного запроса, вы можете просто использовать foreach()
ForAll()
тут воспользуйтесь параллелизмом, это означает выполнение побочного эффекта для более чем одного элемента в коллекции за раз. На самом деле порядок применяется только к результатам запроса (порядок элементов в коллекции результатов), но это не имеет ничего общего с ForAll()
С ForAll()
не влияет на заказ на все.
в PLINQ, цель состоит в том, чтобы максимизировать производительность при сохранении корректность. Запрос должен выполняться как как можно быстрее, но все еще производят правильный результат. В некоторых случаях, корректность требует порядок исходной последовательности для сохранения
отметим, что ForAll()
не преобразует коллекцию (это не я.e проецирование в новую коллекцию), это исключительно для выполнения побочных эффектов на результаты PLINQ запрос.
означает ли это, что упорядоченное выполнение метода ForAll никогда не гарантируется?
Yes-заказ не гарантируется.
распараллеливание означает, что работа распределяется по разным потокам, а их отдельные выходы затем объединяются.
Если вам нужно заказать вывод, не используйте PLinq-или добавьте какой-то более поздний шаг, чтобы вернуть заказ.
кроме того, если вы обращаетесь к таким объектам, как StringBuilder из выполнения plinq, затем убедитесь, что эти объекты являются потокобезопасными, а также имейте в виду, что эта потокобезопасность может фактически сделать plinq медленнее, чем непараллельный linq.