Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

5 лет назад
Открыть в
День 1074. #ЗаметкиНаПолях #AsyncTips Параллельное агрегирование Задача: требуется агрегировать результаты (суммирование значений или вычисление среднего) при завершении параллельной операции. Решение Для поддержки агрегирования класс Parallel использует концепцию локальных значений — переменных, существующих локально внутри параллельного цикла. Это означает, что тело цикла может просто обратиться к значению напрямую, без необходимости синхронизации. Когда цикл готов к агрегированию всех своих локальных результатов, он делает это с помощью делегата localFinally. Следует отметить, что делегату localFinally нужно синхронизировать доступ к переменной для хранения результата. Пример параллельного суммирования:
int ParallelSum(IEnumerable<int> values)
{
  int result = 0;
  Parallel.ForEach(source: values, 
    localInit: () => 0, 
    body: (item, state, localValue) => 
      localValue + item, 
    localFinally: localValue =>
      Interlocked.Add(ref result, localValue)
  ); 
  return result;
}

В Parallel LINQ реализована более понятная поддержка агрегирования, чем в классе Parallel:
int ParallelSum(IEnumerable<int> values)
{ 
  return values.AsParallel().Sum();
}

На самом деле в PLINQ реализована встроенная поддержка многих распространённых операторов (например, Sum). Также предусмотрена обобщённая поддержка агрегирования с оператором Aggregate:
int ParallelSum(IEnumerable<int> values)
{
  return values.AsParallel().Aggregate( 
    seed: 0, 
    func: (sum, item) => sum + item 
  );
}

Если вы уже используете класс Parallel, следует использовать его поддержку агрегирования. В остальных случаях поддержка в PLINQ, как правило, более выразительна, а код получается короче. UPD: Обновил пример ParallelSum примером из документации с использованием Interlocked.Add вместо lock. Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 4.