Параметры слияние в 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 | None |
Skip | None |
Take | None |
Where | нет |
Все остальные операторы запроса PLINQ могут игнорировать указанные пользователем параметры слияния. Некоторые операторы запроса, например Reverse и OrderBy, не могут вернуть ни одного элемента результата, пока не будут созданы и упорядочены все элементы. Таким образом, если в запросе есть параметр ParallelMergeOptions и оператор типа Reverse, этот параметр слияния при обработке не применяется, пока не завершится выдача результатов этого оператора.
Поддержка некоторых параметров слияния некоторыми операторами зависит от типа исходной последовательности и наличия оператора AsOrdered в более ранней позиции этого запроса. ForAll всегда использует NotBuffered, то есть возвращает все элементы немедленно. OrderBy всегда использует FullyBuffered, то есть сортирует полный список перед выдачей любых результатов.