Parallel LINQ (PLINQ) в C#. Параметры слияния в PLINQ (методы WithMergeOptions и ForAll)

При параллельном выполнении запроса PLINQ разделяет исходную последовательность на несколько частей, каждая из которых обрабатывается в отдельном потоке.  Когда нам необходимо использовать результаты вычислений в главном потоке приложения, например в цикле foreach, то полученные в каждом потоке результаты объединяются снова в одну последовательность.  PLINQ может выполнять разные типы слияния в зависимости от операторов, которые присутствуют в запросе. Для потока ожидающего такой результат может пройти достаточно большой период времени, пока появятся первые результаты полностью буферизованного запроса. Однако, используя различные варианты слияния в PLINQ, в некоторых случаях, мы можем ускорить работу приложения и повысить его производительность.

Параметры слияния в PLINQ. Метод WithMergeOptions

Метод WithMergeOptions позволяет указать PLINQ желаемый вариант слияния. При этом, следует отметить, что не все методы PLINQ поддерживают нестандартные варианты слияния итоговой последовательности (об этом ниже). Пример использования метода WithMergeOptions представлен ниже.

static void Main(string[] args)
{
    var source = Enumerable.Range(0, 100);
    var data = source.AsParallel()
        .WithMergeOptions(ParallelMergeOptions.FullyBuffered)//все выходные данные собираются в единый буфер, и лишь затем возвращаются пользователю
        .Select(x => x * x);

    foreach ( var item in data) 
    {
        Console.WriteLine(item);    
    }
}

WithMergeOptions в качестве единственного параметра принимает перечисление ParallelMergeOptions, включающее в себя следующие значения:

  • Not Buffered —  требует немедленно возвращать каждый обработанный элемент из каждого потока сразу же после его создания (вычисления). Если в запросе присутствует оператор AsOrdered, то порядок исходных элементов будет сохранен.
  • Auto Buffered — запрос собирает элементы в буфер и затем периодически выдает все содержимое буфера сразу потоку-потребителю. Размер буфера и точное поведение выдачи настроить нельзя.
  • FullyBuffered — все выходные данные запроса собираются в единый буфер, и лишь затем возвращаются потоку-потребителю. В этом режиме потребуется больше всего времени до передачи первого элемента в поток-потребитель, но зато полные результаты могут быть получены быстрее, чем при использованием других вариантов.

Какие запросы PLINQ поддерживают различные параметры слияния?

Ниже представлены запросы PLINQ поддерживающие параметры слияния и их ограничения:

Оператор Ограничения
AsEnumerable Отсутствуют
Cast Отсутствуют
Concat Неупорядоченные запросы, использующие в качестве источника только массив или список.
DefaultIfEmpty Отсутствуют
OfType Отсутствуют
Reverse Неупорядоченные запросы, использующие в качестве источника только массив или список.
Select Отсутствуют
SelectMany Нет
Skip Нет
Take Нет
Where Отсутствуют

Если запрос не поддерживает различные параметры слияния, то указанное в методе WithMergeOptions значение просто игнорируется.

Метод ForAll

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

static void Main(string[] args)
{
    var source = Enumerable.Range(0, 100);
    source.AsParallel()
        .Select(x => x * x)
        .ForAll(Console.WriteLine);
}

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

Итого

Используя метод WithMergeOptions в PLNQ мы можем, в некоторых случаях, повысить производительность приложения, указав требуемый параметр слияния для итоговой последовательности. При этом, если у нас нет необходимости дожидаться формирования всей последовательности, то, для повышения производительности приложения мы можем использовать метод ForAll, которые по умолчанию вообще не использует буферизации и сразу выдает очередной вычисленный элемент последовательности потоку-потребителю.

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