Parallel LINQ (PLINQ) в C#. Метод AsParallel

Начиная с .NET 4.0, в пространство имен System.Linq был добавлен класс ParallelEnumerable, позволяющий выполнять запросы к источнику данных в параллельном режиме. При обработке запроса, по умолчанию, LINQ обрабатывает все элементы коллекции последовательно, однако, PLINQ позволяет разбить исходную последовательность элементов на сегменты и обработать каждый сегмент параллельно, используя возможности всех процессоров в системе. Для того, чтобы воспользоваться возможностями PLINQ необходимо явно указать платформе, что мы хотим обработать запрос в параллельном режиме. Для этого мы должны использовать метод AsParallel().

Пример параллельной обработки запроса

Рассмотрим следующий пример, показывающий работу PLINQ. Допустим, нам необходимо получить значения синусов углов от 0 до 360 градусов. Вначале выполним запрос в последовательном режиме:

namespace PLINQ
{
    internal class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<int> range = Enumerable.Range(0, 360);
            var sin = range.Select(s => (Angle: s, Sin: Math.Sin(s * Math.PI / 180)));
            foreach (var i in sin) 
            {
                Console.WriteLine($"Синус угла {i.Angle} равен {i.Sin}");
            }
        }
    }
}

В результате, в консоли мы увидим следующие значения:

Синус угла 0 равен 0
Синус угла 1 равен 0,01745240643728351
Синус угла 2 равен 0,03489949670250097
Синус угла 3 равен 0,05233595624294383
Синус угла 4 равен 0,0697564737441253
Синус угла 5 равен 0,08715574274765817
Синус угла 6 равен 0,10452846326765346
Синус угла 7 равен 0,12186934340514748
Синус угла 8 равен 0,13917310096006544
Синус угла 9 равен 0,15643446504023087
Синус угла 10 равен 0,17364817766693033
Синус угла 11 равен 0,1908089953765448
Синус угла 12 равен 0,20791169081775931
…..

Как можно видеть по выводу консоли, вся последовательность была обработана последовательно. Теперь укажем платформе, что мы хотим обработать последовательности в параллельном режиме. Для этого воспользуемся методом AsParallel() следующим образом:

namespace PLINQ
{
    internal class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<int> range = Enumerable.Range(0, 360);
            var sin = range.AsParallel().Select(s => (Angle: s, Sin: Math.Sin(s * Math.PI / 180)));
            foreach (var i in sin) 
            {
                Console.WriteLine($"Синус угла {i.Angle} равен {i.Sin}");
            }
        }
    }
}

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

Синус угла 1 равен 0,01745240643728351
Синус угла 2 равен 0,03489949670250097
Синус угла 0 равен 0
Синус угла 114 равен 0,913545457642601
Синус угла 273 равен -0,9986295347545738
Синус угла 3 равен 0,05233595624294383
Синус угла 123 равен 0,838670567945424
Синус угла 274 равен -0,9975640502598243
Синус угла 4 равен 0,0697564737441253
Синус угла 140 равен 0,6427876096865395
Синус угла 275 равен -0,9961946980917455

Таким образом, в ряде случаев, мы можем добиться увеличения производительности нашего приложения за счёт распараллеливания запросов к источнику данных. При этом стоит отметить некоторые особенности работы PLINQ, которые, в дальнейшем, помогут нам в работе.

Основные моменты работы PLINQ в C#

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

Итого

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

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