Mergeoptionen in PLINQ

Wenn eine Abfrage als parallel ausgeführt wird, partitioniert PLINQ die Quellsequenz, sodass mehrere Threads gleichzeitig an verschiedenen Teilen arbeiten können, in der Regel an separaten Threads. Wenn die Ergebnisse in einem einzelnen Thread verarbeitet werden sollen, z.B. in einer foreach-Schleife (For Each in Visual Basic), müssen die Ergebnisse der einzelnen Threads wieder zu einer einzigen Sequenz zusammengeführt werden. Welche Art der Zusammenführung PLINQ ausführt, hängt von den Operatoren ab, die in der Abfrage vorhanden sind. Beispielsweise müssen Operatoren, die die Ergebnisse in eine neue Reihenfolge stellen, alle Elemente aus allen Threads puffern. Aus der Perspektive des nutzenden Threads (die mit der des Anwendungsbenutzers identisch ist) könnte eine vollständig gepufferte Abfrage für einen beachtlichen Zeitraum ausgeführt werden, bevor sie das erste Ergebnis liefert. Andere Operatoren sind standardmäßig teilweise gepuffert. Sie stellen ihre Ergebnisse batchweise bereit. Ein Operator, ForAll, wird nicht standardmäßig gepuffert. Er stellt alle Elemente aus allen Threads sofort bereit.

Wie im folgenden Beispiel gezeigt, können Sie mithilfe der WithMergeOptions-Methode einen Hinweis für PLINQ bereitstellen, der die Art der Zusammenführung angibt.

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)

Das vollständige Beispiel finden Sie unter Vorgehensweise: Angeben von Mergeoptionen in PLINQ.

Wenn die betreffende Abfrage die angeforderte Option nicht unterstützen kann, wird die Option einfach ignoriert. In den meisten Fällen müssen Sie keine Mergeoption für eine PLINQ-Abfrage angeben. In einigen Fällen stellen Sie jedoch möglicherweise durch Testen und Messen fest, dass eine Abfrage am besten in einem nicht standardmäßigen Modus ausgeführt wird. Eine übliche Verwendung dieser Option ist, zu erzwingen, dass ein Blockzusammenführungs-Operator seine Ergebnisse streamt, um eine reaktionsfreudigere Benutzeroberfläche bereitzustellen.

ParallelMergeOptions

Die ParallelMergeOptions-Enumeration enthält die folgenden Optionen, die für unterstützte Abfrageformen angeben, wie die endgültige Ausgabe der Abfrage bereitgestellt wird, wenn die Ergebnisse in einem einzelnen Thread verarbeitet werden:

  • Not Buffered

    Die NotBuffered-Option bewirkt, dass jedes verarbeitete Element aus jedem Thread zurückgegeben wird, sobald seine Verarbeitung abgeschlossen ist. Dieses Verhalten ist analog zum „Streamen“ der Ausgabe. Wenn der AsOrdered-Operator in der Abfrage vorhanden ist, behält NotBuffered die Reihenfolge der Quellelemente bei. Obwohl NotBuffered beginnt, Ergebnisse bereitzustellen, sobald sie verfügbar sind, kann die Gesamtzeit zum Erzeugen aller Ergebnisse dennoch länger sein als mit einer der anderen Mergeoptionen.

  • Auto Buffered

    Die AutoBuffered-Option bewirkt, dass die Abfrage Elemente in einem Puffer sammelt und dann in regelmäßigen Abständen den gesamten Pufferinhalt für den verarbeitenden Thread bereitstellt. Dies ist analog zum Bereitstellen der Quelldaten in „Blöcken“ statt Verwendung des „Streamverhaltens“ von NotBuffered. AutoBuffered benötigt möglicherweise mehr Zeit als NotBuffered, um das erste Element für den verarbeitenden Thread verfügbar zu machen. Die Größe des Puffers und das genaue Ausgabeverhalten sind nicht konfigurierbar und variieren abhängig von verschiedenen, von der Abfrage abhängigen Faktoren.

  • FullyBuffered

    Die FullyBuffered-Option bewirkt, dass die Ausgabe der gesamten Abfrage gepuffert wird, bevor eines der Elemente bereitgestellt wird. Wenn Sie diese Option verwenden, kann es länger dauern, bis das erste Element für den verarbeitenden Thread verfügbar ist, aber die vollständigen Ergebnisse könnten dennoch schneller erzeugt werden als mit den anderen Optionen.

Abfrageoperatoren, die Mergeoptionen unterstützen

Die folgende Tabelle enthält die Operatoren, die alle Mergeoptionen unterstützen, und etwaige Einschränkungen.

Operator Beschränkungen
AsEnumerable Keine
Cast Keine
Concat Nicht geordnete Abfragen, die nur über eine Array- oder Listenquelle verfügen.
DefaultIfEmpty Keine
OfType Keine
Reverse Nicht geordnete Abfragen, die nur über eine Array- oder Listenquelle verfügen.
Select Keine
SelectMany Nein
Skip Nein
Take Nein
Where Keine

Alle anderen PLINQ-Abfrageoperatoren werden möglicherweise von durch den Benutzer bereitgestellten Mergeoptionen ignoriert. Einige Abfrageoperatoren, z.B. Reverse und OrderBy, können erst dann Elemente bereitstellen, wenn alle erzeugt und neu angeordnet wurden. Wenn ParallelMergeOptions in einer Abfrage verwendet wird, die auch einen Operator wie z.B. Reverse enthält, wird darum das Zusammenführungsverhalten erst dann in der Abfrage angewendet, nachdem dieser Operator seine Ergebnisse erzeugt hat.

Die Fähigkeit einiger Operatoren, Mergeoptionen zu behandeln, hängt vom Typ der Quellsequenz ab, und ob der AsOrdered-Operator früher in der Abfrage verwendet wurde. ForAll ist immer NotBuffered; er stellt seine Elemente sofort bereit. OrderBy ist immer FullyBuffered; er muss die gesamte Liste vor der Bereitstellung sortieren.

Siehe auch