Parallel LINQ (PLINQ) в C#. Режим выполнения запроса (метод WithExecutionMode)

Не все запросы могут стать автоматически быстрее при параллельном выполнении. Например, если запрос содержит только один пользовательский делегат с небольшим числом задач, то такой запрос последовательно выполняется быстрее. Это связано с  различными дополнительными накладными расходами на управление параллельным выполнением. Однако, PLINQ позволяет, при необходимости, указать тот режим выполнения запроса, который вам необходим. Для этого используется один из методов расширения PLINQ —  WithExecutionMode.

Метод WithExecutionMode

В некоторых случаях у нас может быть больше сведений о сложности и ресурсоемкости запроса, чем доступно PLINQ. Когда иы точно уверены в том, что делегат в запросе затратный и в любом случае выиграет от применения параллелизации, то в этом случае мы можем указать PLINQ, что такой запрос должен выполняться только в параллельном режиме. Например,

IEnumerable<int> range = Enumerable.Range(0, 10000000);
var square = range.AsParallel()
    .WithExecutionMode(ParallelExecutionMode.ForceParallelism) //указываем, что запрос должен выполняться в параллельном режиме
    .Select(s => Math.Sqrt(s));

здесь мы вызываем метод WithExecutionMode с флагом ParallelExecutionMode.ForceParallelism, заставляя, тем самым, PLINQ обработать запрос в параллельном режиме. При этом, флаг ParallelExecutionMode.ForceParallelism может принимать следующие значения:

Default 0 Параметр по умолчанию. PLINQ изучит структуру запроса и выполнит его в параллельном режиме, только если это может привести к ускорению работы, иначе — PLINQ выполнит данный запрос как обычный запрос LINQ to Objects.
ForceParallelism 1 Выполнять весь запрос параллельно, даже если для этого понадобится использовать алгоритмы, требующие много ресурсов. Этот флаг используется в тех случаях, когда известно, что параллельное выполнение запроса приведет к ускорению, но, при этом, в режиме по умолчанию PLINQ этот запрос выполняет как последовательный.

В каких случаях PLINQ выполняет запрос последовательно?

Есть ряд условий при которых PLINQ по умолчанию будет выполнять запрос последовательно, а именно:

  1. запросы, содержащие предложение Select, а также индексированные инструкции Where, SelectMany или ElementAt после оператора упорядочивания или фильтрации, которые удаляют или изменяют исходные индексы.
  2. запросы, содержащие оператор Take, TakeWhile, Skip или SkipWhile, в которых индексы исходной последовательности не сохраняют исходный порядок.
  3. запросы, которые содержат Zip или SequenceEquals, за исключением случаев, когда один из источников данных содержит изначально упорядоченный индекс, а другой источник данных можно проиндексировать (например, массив или IList(T)).
  4. запросы, которые содержат оператор Concat, если он не применяется к индексируемым источникам данных.
  5. запросы, содержащие оператор Reverse, если он не применяется к индексируемым источникам данных.

Итого

По умолчанию PLINQ анализирует запрос и, в зависимости от результата анализа, самостоятельно выбирает режим работы с запросом — параллельно или последовательно. Однако, если мы уверены, что в параллельном режиме мы точно повысим производительность нашего приложения, то мы можем принудительно заставить PLINQ выполнять запрос параллельно. Для этого мы используем метод WithExecutionMode.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии