День 1126. #ЗаметкиНаПолях #AsyncTips
Parallel LINQ
Задача: требуется выполнить параллельную обработку последовательности данных, чтобы сгенерировать другую их последовательность или обобщение этих данных.
Решение
Многие разработчики знакомы с технологией LINQ, позволяющей программировать вычисления с последовательностями, работающей по принципу вытягивания. Parallel LINQ (PLINQ) расширяет эту поддержку LINQ параллельной обработкой.
PLINQ хорошо работает в потоковых сценариях, которые получают последовательность входных значений и производят последовательность выходных значений. Следующий простой пример просто умножает каждый элемент последовательности на 2 (в реальных сценариях выполняются гораздо более серьезные вычисления):
IEnumerable<int> Multiply(
IEnumerable<int> vals)
{
return vals.AsParallel()
.Select(value => value * 2);
}
Пример может генерировать свои выходные значения в любом порядке; это поведение используется по умолчанию в Parallel LINQ. Также можно потребовать, чтобы сохранялся исходный порядок. В следующем примере обработка ведется параллельно, но с сохранением исходного порядка:
IEnumerable<int> Multiply(
IEnumerable<int> vals)
{
return vals.AsParallel()
.AsOrdered().Select(value => value * 2);
}
Другое логичное применение Parallel LINQ — агрегирование или обобщение данных в параллельном режиме. В следующем примере выполняется параллельное суммирование:
int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Sum();
}
Класс Parallel хорошо подходит для многих сценариев, но код PLINQ получается более простым при агрегировании или преобразовании одной последовательности в другую. Следует помнить, что класс Parallel ведет себя более корректно с другими процессами в системе, чем PLINQ; этот фактор становится особенно существенным при выполнении параллельной обработки на серверной машине.
PLINQ предоставляет параллельные версии многих операторов, включая фильтрацию (Where), проекцию (Select) и разные виды агрегирования, такие как Sum, Average и более общую форму Aggregate. В общем случае всё, что можно сделать в обычном LINQ, также можно сделать в параллельном режиме в PLINQ. В результате PLINQ становится отличным кандидатом для обработки существующего кода LINQ, который выиграл бы от выполнения в параллельном режиме.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 4.