Поделиться через


Варианты объединения в PLINQ

Когда запрос выполняется как параллельный, PLINQ секционирует исходную последовательность, чтобы несколько потоков могли работать одновременно с различными частями, как правило, в отдельных потоках. Если результаты должны использоваться в одном потоке, например в foreach цикле (For Each в Visual Basic), результаты каждого потока должны быть объединены обратно в одну последовательность. Тип слияния, выполняемого PLINQ, зависит от операторов, присутствующих в запросе. Например, операторы, налагающие новый порядок в результатах, должны буферизать все элементы из всех потоков. С точки зрения потока-потребителя (который также соответствует пользователю приложения) полностью буферизованный запрос может выполняться в течение заметного периода времени, прежде чем выдаст свой первый результат. Другие операторы, по умолчанию, частично буферизаются; они дают свои результаты в пакетах. Оператор ForAll не буферизуется по умолчанию. Он немедленно выдает все элементы из всех потоков.

Используя WithMergeOptions метод, как показано в следующем примере, можно дать инструкцию PLINQ о том, какой тип объединения необходимо выполнить.

var scanLines = from n in nums.AsParallel()
                    .WithMergeOptions(ParallelMergeOptions.NotBuffered)
                where n % 2 == 0
                select ExpensiveFunc(n);
Dim scanlines = From n In nums.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered)
                Where n Mod 2 = 0
                Select ExpensiveFunc(n)

Полный пример см. в разделе "Практическое руководство. Указание параметров слияния в PLINQ".

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

ParallelMergeOptions

Перечисление ParallelMergeOptions включает следующие параметры, которые указывают для поддерживаемых фигур запросов, как конечные выходные данные запроса получаются при использовании результатов в одном потоке:

  • Not Buffered

    Параметр NotBuffered обеспечивает возврат каждого обработанного элемента из каждого потока сразу после его создания. Это поведение аналогично "потоковой передаче" выходных данных. AsOrdered Если оператор присутствует в запросе, NotBuffered сохраняет порядок исходных элементов. Хотя NotBuffered начинает получать результаты сразу после их доступности, общее время создания всех результатов может быть дольше, чем использование одного из других вариантов слияния.

  • Auto Buffered

    Эта AutoBuffered опция заставляет запрос собирать элементы в буфер и затем периодически передавать все содержимое буфера одновременно в поток потребителя. Это аналогично извлечению исходных данных по кускам вместо использования поведения потоковой передачи NotBuffered. AutoBuffered может занять больше времени, чем NotBuffered, прежде чем первый элемент станет доступен в потребляемом потоке. Размер буфера и точное поведение освобождения ресурсов не настраиваются и могут отличаться в зависимости от различных факторов, связанных с запросом.

  • FullyBuffered

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

Операторы запросов, поддерживающие параметры слияния

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

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

Все остальные операторы запросов PLINQ могут игнорировать предоставленные пользователем параметры слияния. Некоторые операторы запросов, например, Reverse и OrderBy, не могут выдавать элементы до тех пор, пока все не будут созданы и переупорядочены. Таким образом, если ParallelMergeOptions используется в запросе, который также содержит оператор, например Reverse, поведение слияния не будет применяться в запросе до тех пор, пока этот оператор не выдаст результаты.

Возможность некоторых операторов обрабатывать параметры слияния зависит от типа исходной последовательности и того, использовался ли AsOrdered оператор ранее в запросе. ForAll всегда NotBuffered; он немедленно выдает свои элементы. OrderBy всегда FullyBuffered; он должен отсортировать весь список до того, как он выдаст результат.

См. также