Параметры слияние в PLINQMerge Options in PLINQ

Когда запрос выполняется как параллельный, PLINQ разделяет исходную последовательность между несколькими потоками, чтобы они могли параллельно работать с разными частями.When a query is executing as parallel, PLINQ partitions the source sequence so that multiple threads can work on different parts concurrently, typically on separate threads. Если результаты будут использоваться в одном потоке, например в цикле foreach (For Each в Visual Basic), то полученные в каждом потоке результаты нужно объединить в одну последовательность.If the results are to be consumed on one thread, for example, in a foreach (For Each in Visual Basic) loop, then the results from every thread must be merged back into one sequence. PLINQ может выполнять разные типы слияния в зависимости от операторов, которые присутствуют в запросе.The kind of merge that PLINQ performs depends on the operators that are present in the query. Например, для операторов, изменяющих порядок результатов, необходимо собрать в буфер все элементы из всех потоков.For example, operators that impose a new order on the results must buffer all elements from all threads. Для потока ожидающего такой результат (и для пользователя приложения) может пройти достаточно большой период времени, пока появятся первые результаты полностью буферизованного запроса.From the perspective of the consuming thread (which is also that of the application user) a fully buffered query might run for a noticeable period of time before it produces its first result. Другие операторы по умолчанию используют частичную буферизацию, то есть возвращают результаты несколькими пакетами.Other operators, by default, are partially buffered; they yield their results in batches. Один оператор (ForAll) по умолчанию не использует буферизацию.One operator, ForAll is not buffered by default. Он немедленно выдает все элементы из всех потоков.It yields all elements from all threads immediately.

С помощью метода WithMergeOptions, как показано в следующем примере, можно предоставить PLINQ подсказку с требуемым типом слияния.By using the WithMergeOptions method, as shown in the following example, you can provide a hint to PLINQ that indicates what kind of merging to perform.

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.For the complete example, see How to: Specify Merge Options in PLINQ.

Если выполняемый запрос не поддерживает запрошенный вариант, этот параметр просто игнорируется.If the particular query cannot support the requested option, then the option will just be ignored. В большинстве случаев нет необходимости указывать параметр слияния для запроса PLINQ.In most cases, you do not have to specify a merge option for a PLINQ query. Однако, в некоторых случаях тесты и (или) измерения показывают, что запрос лучше всего выполняется в нестандартном режиме.However, in some cases you may find by testing and measurement that a query executes best in a non-default mode. Чаще всего этот параметр используется, чтобы заставить оператор с частичной буферизацией выдавать все результаты в общем потоке. Это позволяет улучшить скорость реагирования интерфейса на действия пользователя.A common use of this option is to force a chunk-merging operator to stream its results in order to provide a more responsive user interface.

ParallelMergeOptionsParallelMergeOptions

Перечисление ParallelMergeOptions включает следующие параметры, которые позволяют выбрать для поддерживаемых форм запросов режим упорядочивания конечных результатов, если эти результаты используются в одном потоке.The ParallelMergeOptions enumeration includes the following options that specify, for supported query shapes, how the final output of the query is yielded when the results are consumed on one thread:

  • Not Buffered

    NotBuffered требует немедленно возвращать каждый обработанный элемент из каждого потока сразу же после его создания.The NotBuffered option causes each processed element to be returned from each thread as soon as it is produced. Это поведение аналогично "потоковой передаче" выходных данных.This behavior is analogous to "streaming" the output. Если в запросе присутствует оператор AsOrdered, NotBuffered сохраняет порядок исходных элементов.If the AsOrdered operator is present in the query, NotBuffered preserves the order of the source elements. Несмотря на то, что в режиме NotBuffered немедленно возвращаются все готовые результаты, общее время обработки все равно может оказаться выше, чем для других параметров слияния.Although NotBuffered starts yielding results as soon as they're available,, the total time to produce all the results might still be longer than using one of the other merge options.

  • Auto Buffered

    При использовании параметра AutoBuffered запрос собирает элементы в буфер и затем периодически выдает все содержимое буфера сразу потоку-потребителю.The AutoBuffered option causes the query to collect elements into a buffer and then periodically yield the buffer contents all at once to the consuming thread. Такое поведение аналогично выдаче исходных данных блоками, в отличие от потоковой передачи в режиме NotBuffered.This is analogous to yielding the source data in "chunks" instead of using the "streaming" behavior of NotBuffered. При выборе AutoBuffered может потребоваться больше времени, чем при NotBuffered, чтобы передать первый элемент в поток-потребитель.AutoBuffered may take longer than NotBuffered to make the first element available on the consuming thread. Размер буфера и точное поведение выдачи настроить нельзя, и они могут быть разными в зависимости от нескольких характеристик запроса.The size of the buffer and the exact yielding behavior are not configurable and may vary, depending on various factors that relate to the query.

  • FullyBuffered

    Параметр FullyBuffered требует собирать все выходные данные запроса в единый буфер, и лишь затем возвращать его элементы.The FullyBuffered option causes the output of the whole query to be buffered before any of the elements are yielded. В этом режиме потребуется больше всего времени до передачи первого элемента в поток-потребитель, но зато полные результаты могут быть получены быстрее, чем при использованием других вариантов.When you use this option, it can take longer before the first element is available on the consuming thread, but the complete results might still be produced faster than by using the other options.

Операторы запроса, поддерживающие параметры слиянияQuery Operators that Support Merge Options

В следующей таблице перечислены операторы, которые поддерживают все параметры слияния, а также указаны возможные ограничения.The following table lists the operators that support all merge option modes, subject to the specified restrictions.

ОператорOperator ОграниченияRestrictions
AsEnumerable НетNone
Cast НетNone
Concat Неупорядоченные запросы, использующие в качестве источника только массив или список.Non-ordered queries that have an Array or List source only.
DefaultIfEmpty НетNone
OfType НетNone
Reverse Неупорядоченные запросы, использующие в качестве источника только массив или список.Non-ordered queries that have an Array or List source only.
Select НетNone
SelectMany НетNone
Skip НетNone
Take НетNone
Where НетNone

Все остальные операторы запроса PLINQ могут игнорировать указанные пользователем параметры слияния.All other PLINQ query operators might ignore user-provided merge options. Некоторые операторы запроса, например Reverse и OrderBy, не могут вернуть ни одного элемента результата, пока не будут созданы и упорядочены все элементы.Some query operators, for example, Reverse and OrderBy, cannot yield any elements until all have been produced and reordered. Таким образом, если в запросе есть параметр ParallelMergeOptions и оператор типа Reverse, этот параметр слияния при обработке не применяется, пока не завершится выдача результатов этого оператора.Therefore, when ParallelMergeOptions is used in a query that also contains an operator such as Reverse, the merge behavior will not be applied in the query until after that operator has produced its results.

Поддержка некоторых параметров слияния некоторыми операторами зависит от типа исходной последовательности и наличия оператора AsOrdered в более ранней позиции этого запроса.The ability of some operators to handle merge options depends on the type of the source sequence, and whether the AsOrdered operator was used earlier in the query. ForAll всегда использует NotBuffered, то есть возвращает все элементы немедленно.ForAll is always NotBuffered ; it yields its elements immediately. OrderBy всегда использует FullyBuffered, то есть сортирует полный список перед выдачей любых результатов.OrderBy is always FullyBuffered; it must sort the whole list before it yields.

См. такжеSee also