Datenfluss (Task Parallel Library)

.NET Framework (current version)
 

Veröffentlicht: Oktober 2016

Die Task Parallel Library (TPL) stellt Datenflusskomponenten, um die Stabilität der parallelitätsfähigen Applikationen zu erhöhen. Diese Datenflusskomponenten werden zusammen als bezeichnet die TPL-Datenflussbibliothek. Dieses Datenflussmodell begünstigt die akteurbasierte Programmierung durch eine prozessinterne Nachrichtenübergabe für simple Datenfluss- und Pipelineaufgaben. Die Datenflusskomponenten basieren auf den Typen und der Planungsinfrastruktur der TPL und sind in die C#-, Visual Basic- und F#-Sprachunterstützung für asynchrone Programmierung integriert. Diese Datenflusskomponenten sind hilfreich, wenn mehrere Vorgänge vorliegen, die asynchron miteinander kommunizieren müssen, oder wenn Sie Daten verarbeiten möchten, die gerade verfügbar werden. Denken Sie beispielsweise an eine Anwendung, die Bilddaten von einer Webcam verarbeitet. Durch das Datenflussmodell kann die Anwendung Bildframes verarbeiten, sobald diese verfügbar sind. Wenn die Anwendung Bildframes beispielsweise durch hell Korrektur oder rote-Augen, können Sie erstellen ein Pipeline von Datenflusskomponenten. Jede Phase der Pipeline kann grober strukturierte Parallelitätsfunktionen verwenden, wie z. B. die von der TPL bereitgestellten Funktionen zum Transformieren des Bilds.

Dieses Dokument enthält eine Übersicht über die TPL-Datenflussbibliothek. Es bietet Informationen über das Programmiermodell, die vordefinierten Datenflussblocktypen sowie die Konfiguration der Datenflussblöcke für die speziellen Anforderungen Ihrer Anwendungen.

System_CAPS_ICON_tip.jpg Tipp

Die TPL-Datenflussbibliothek (System.Threading.Tasks.Dataflow Namespace) ist nicht mit verteilt die .NET Framework 4.5. So installieren Sie die System.Threading.Tasks.Dataflow -Namespace öffnen Sie das Projekt in Visual Studio 2012, wählen Sie NuGet-Pakete verwalten aus dem Menü Projekt, und suchen Sie online nach der Microsoft.Tpl.Dataflow Paket.

Dieses Dokument enthält folgende Abschnitte:

Die TPL-Datenflussbibliothek bietet eine Grundlage für die Nachrichtenübergabe und die Parallelisierung CPU-intensiver und E/A-intensiver Anwendungen mit hohem Durchsatz und niedriger Latenz. Außerdem erhalten Sie damit explizite Kontrolle darüber, wie Daten gepuffert und im System übermittelt werden. Stellen Sie sich zum besseren Verständnis des Datenflussprogrammiermodells eine Anwendung vor, die Bilder asynchron vom Datenträger lädt und ein Kompositum dieser Bilder erstellt. Herkömmliche Programmiermodelle erfordern in der Regel die Verwendung von Rückrufen und Synchronisierungsobjekten wie Sperren, um Aufgaben und den Zugriff auf freigegebene Daten zu koordinieren. Mit dem Datenflussprogrammiermodell können Sie Datenflussobjekte erstellen, die Bilder beim Lesen vom Datenträger verarbeiten. Unter dem Datenflussmodell deklarieren Sie, wie Daten behandelt werden, sobald diese verfügbar werden, und legen außerdem Abhängigkeiten zwischen Daten fest. Da die Laufzeit Abhängigkeiten zwischen Daten verwaltet, können Sie häufig die Anforderung vermeiden, Zugriff auf freigegebene Daten synchronisieren zu müssen. Da die Arbeit von der Laufzeit basierend auf dem asynchronen Eintreffen von Daten geplant wird, können Reaktionsgeschwindigkeit und Durchsatz des Datenflusses verbessert werden, indem die zugrunde liegenden Threads effizient verwaltet werden. Ein Beispiel, das Datenflussprogrammiermodell bildverarbeitung in einer Windows Forms-Anwendung implementiert, finden Sie unter Exemplarische Vorgehensweise: Datenfluss in einer Windows Forms-Anwendung.

Quellen und Ziele

Die TPL-Datenflussbibliothek besteht aus Datenflussblöcke, Daten Puffern und verarbeiten die Daten sind strukturiert. Die TPL definiert drei Arten von Datenflussblöcken: quellblöcken, Ziel Blöcke, und weitergabeblöcke. Ein Quellblock fungiert als Datenquelle, aus der gelesen werden kann. Ein Zielblock fungiert als Datenempfänger, in den geschrieben werden kann. Ein Weitergabeblock fungiert als Quellblock und als Zielblock, aus dem gelesen und in den geschrieben werden kann. Die TPL definiert die System.Threading.Tasks.Dataflow.ISourceBlock<> </> > Schnittstelle, um Quellen darzustellen System.Threading.Tasks.Dataflow.ITargetBlock<> </> > um Ziele darzustellen und System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput, TOutput> um Weitergaben darzustellen.</TInput, TOutput> IPropagatorBlock<TInput, TOutput> erbt von ISourceBlock<>>, und ITargetBlock<>>.</TInput, TOutput>

Die TPL-Datenflussbibliothek enthält mehrere vordefinierte datenflussblocktypen, die Implementierung der ISourceBlock<>>, ITargetBlock<>>, und IPropagatorBlock<TInput, TOutput> Schnittstellen.</TInput, TOutput> Diese datenflussblocktypen werden in diesem Dokument im Abschnitt beschriebenen vordefinierte Datenflussblocktypen.

Verbinden von Blöcken

Sie können Datenflussblöcke mit Formular verbinden Pipelines, lineare Sequenzen von Datenflussblöcken, oder Netzwerke, Diagramme von Datenflussblöcken konfiguriert wird. Eine Pipeline ist eine Form von Netzwerk. In einer Pipeline oder einem Netzwerk geben Quellen asynchron Daten an Ziele weiter, sobald diese Daten verfügbar werden. Die ISourceBlock<>>. VerknüpfungMit -Methode verknüpft einen quelldatenflussblock mit einem Zielblock. Eine Quelle kann mit null oder mehr Zielen verknüpft werden. Ziele können mit null oder mehr Quellen verknüpft werden. Sie können Datenflussblöcke in einer Pipeline oder einem Netzwerk gleichzeitig hinzufügen oder entfernen. Die vordefinierten Datenflussblocktypen behandeln alle Threadsicherheitsaspekte bezüglich Verknüpfungen und des Lösens von Verknüpfungen.

Ein Beispiel für die Verbindung von Datenflussblöcken zum Erstellen einer einfachen Pipeline, finden Sie unter Exemplarische Vorgehensweise: Erstellen einer Datenflusspipeline. Ein Beispiel für die Verbindung von Datenflussblöcken zum ein komplexes Netzwerks, finden Sie unter Exemplarische Vorgehensweise: Datenfluss in einer Windows Forms-Anwendung. Ein Beispiel für die Verknüpfung ein Ziels mit einer Quelle, nachdem die Quelle dem Ziel eine Nachricht anbietet, finden Sie unter wie: Verknüpfungen für Datenflussblöcke.

Filtern

Beim Aufrufen der ISourceBlock<>>. VerknüpfungMit Methode, um eine Quelle in ein Ziel, verknüpfen Sie einen Delegaten, der bestimmt, ob der Zielblock akzeptiert oder eine Nachricht basierend auf den Wert der Nachricht ablehnt angeben können. Dieser Filtermechanismus ist eine hilfreiche Möglichkeit, um sicherzustellen, dass nur bestimmte Werte von einem Datenflussblock empfangen werden. Für die meisten der vordefinierten Datenflussblocktypen gilt, dass eine Nachricht von der Quelle dem nächsten Ziel angeboten wird, wenn ein Quellblock mit mehreren Zielblöcken verbunden ist und ein Zielblock die Nachricht ablehnt. Die Reihenfolge, in der Nachrichten von einer Quelle Zielen angeboten werden, wird durch die Quelle definiert und kann je nach Typ der Quelle variieren. Die meisten Quellblocktypen bieten eine Nachricht nicht weiter an, nachdem diese von einem Ziel akzeptiert wurde. Eine Ausnahme von dieser Regel ist die BroadcastBlock<> </> > -Klasse, die jede Nachricht allen Zielen anbietet, auch wenn einige Ziele die Nachricht ablehnen. Ein Beispiel, die Filterung verwendet wird, um nur bestimmte Nachrichten zu verarbeiten, finden Sie unter Exemplarische Vorgehensweise: Datenfluss in einer Windows Forms-Anwendung.

System_CAPS_ICON_important.jpg Wichtig

Da jeder vordefinierte Quelldatenflussblocktyp sicherstellt, dass Nachrichten in der Reihenfolge weitergegeben werden, in der sie empfangen werden, muss jede Nachricht vom Quellblock gelesen werden, bevor der Quellblock die nächste Nachricht verarbeiten kann. Wenn Sie daher Filter verwenden, um mehrere Ziele mit einer Quelle zu verbinden, sollten Sie sicherstellen, dass jede Nachricht von mindestens einem Zielblock empfangen wird. Andernfalls kann bei der Anwendung ein Deadlock auftreten.

Nachrichtenübergabe

Das Datenflussprogrammiermodell bezieht sich auf das Konzept der Nachrichtenübergabe, bei dem unabhängige Komponenten eines Programms miteinander kommunizieren, die Nachrichten gesendet. Eine Möglichkeit, Nachrichten zwischen Anwendungskomponenten weitergegeben wird, rufen Sie die Post<> </> > und DataflowBlock.SendAsync<> </> > Methoden zum Senden von Nachrichten an zieldatenflussblöcke (Post<> </> > agiert synchron, SendAsync<> </> > agiert asynchron) und die empfangen<>>, ReceiveAsync<>>, und TryReceive<> </> > Methoden, um Nachrichten von quellblöcken zu empfangen. Sie können diese Methoden mit Datenflusspipelines oder -netzwerken kombinieren, indem Sie Eingabedaten an den Hauptknoten (ein Zielblock) senden und Ausgabedaten vom Terminalknoten der Pipeline bzw. von den Terminalknoten des Netzwerks (ein oder mehrere Quellblöcke) empfangen. Können Sie auch die auswählen -Methode zum Lesen aus dem ersten der bereitgestellten Quellen, die Daten zur Verfügung und Aktion für diese Daten ausführen.

Quellblöcke bieten Zielblöcken Daten an, durch Aufrufen der ITargetBlock<>>. OfferMessage Methode. Der Zielblock reagiert auf eine angebotene Nachricht auf eine von drei Arten: Er kann die Nachricht akzeptieren, ablehnen oder zurückstellen. Wenn das Ziel die Meldung akzeptiert die OfferMessage -Methode gibt akzeptiert. Wenn das Ziel die Nachricht ablehnt der OfferMessage -Methode gibt abgelehnt. Wenn das Ziel erfordert, dass er nicht mehr alle Nachrichten aus der Quelle empfängt OfferMessage gibt DecliningPermanently. Die vordefinierten Quellblocktypen bieten verknüpften Zielen keine Nachrichten an, nachdem ein solcher Rückgabewert empfangen wird, und die Verknüpfung zu solchen Zielen wird automatisch gelöst.

Wenn ein Zielblock die Nachricht für die spätere Verwendung zurückstellt der OfferMessage -Methode gibt zurückgestellt. Ein Zielblock, eine Nachricht zurückstellt, können spätere Aufrufe der ISourceBlock<>>. ReserveMessage Methode, um zu versuchen, die angebotene Nachricht zu reservieren. In diesem Moment ist die Nachricht entweder weiterhin verfügbar und kann vom Zielblock verwendet werden, oder die Nachricht wurde von einem anderen Ziel angenommen. Wenn der Zielblock die Nachricht später benötigt oder die Nachricht nicht mehr benötigt, ruft er die ISourceBlock<>>. ConsumeMessage oder ReleaseReservation Methode bzw.. Nachrichtenreservierung wird in der Regel von Datenflussblocktypen verwendet, die sich im nicht gierigen Modus befinden. "Nicht gieriger Modus" wird weiter unten in diesem Dokument erläutert. Anstatt zu reservieren eine zurückgestellte Nachricht, ein Zielblock können Sie auch die ISourceBlock<>>. ConsumeMessage -Methode versucht, die zurückgestellte Nachricht direkt zu verarbeiten.

Abschluss von Datenflussblöcken

Datenflussblöcke unterstützen auch das Konzept der Abschluss. Ein Datenflussblock, der sich im abgeschlossenen Zustand befindet, führt keine weitere Arbeit mehr aus. Jeder Datenflussblock verfügt über eine zugeordnete System.Threading.Tasks.Task -Objekts, auch bezeichnet als ein Abschlussaufgabe, den Abschlusszustand des Blocks darstellt. Da Sie warten, können ein Aufgabe -Objekt abgeschlossen wird mithilfe von Abschlussaufgaben, warten, bis einer oder mehreren Terminalknoten eines Datenflussnetzwerks Fertig stellen. Die IDataflowBlock Schnittstelle definiert die vollständig -Methode, die eine Anforderung zum Abschließen der Datenflussblock informiert, und die Abschluss -Eigenschaft, die die Abschlussaufgabe für den Datenflussblock zurückgibt. Beide ISourceBlock<> </> > und ITargetBlock<> </> > erben die IDataflowBlock Schnittstelle.

Es gibt zwei Möglichkeiten, um zu bestimmen, ob ein Datenflussblock ohne Fehler abgeschlossen wurde, ob mindestens ein Fehler aufgetreten ist oder ob er abgebrochen wurde. Die erste Möglichkeit besteht im Aufrufen der "Task.Wait" Methode für die Abschlussaufgabe in einem try - catch Block (Try - Catch in Visual Basic). Das folgende Beispiel erstellt eine ActionBlock<> </> > -Objekt, das löst ArgumentOutOfRangeException ist der Eingabewert kleiner als&0; (null). AggregateException wird ausgelöst, wenn dieses Beispiel ruft warten für die Abschlussaufgabe. Die ArgumentOutOfRangeException erfolgt über die InnerExceptions Eigenschaft der AggregateException Objekt.

         // Create an ActionBlock<int> object that prints its input
         // and throws ArgumentOutOfRangeException if the input
         // is less than zero.
         var throwIfNegative = new ActionBlock<int>(n =>
         {
            Console.WriteLine("n = {0}", n);
            if (n < 0)
            {
               throw new ArgumentOutOfRangeException();
            }
         });

         // Post values to the block.
         throwIfNegative.Post(0);
         throwIfNegative.Post(-1);
         throwIfNegative.Post(1);
         throwIfNegative.Post(-2);
         throwIfNegative.Complete();

         // Wait for completion in a try/catch block.
         try
         {
            throwIfNegative.Completion.Wait();
         }
         catch (AggregateException ae)
         {
            // If an unhandled exception occurs during dataflow processing, all
            // exceptions are propagated through an AggregateException object.
            ae.Handle(e =>
            {
               Console.WriteLine("Encountered {0}: {1}", 
                  e.GetType().Name, e.Message);
               return true;
            });
         }

         /* Output:
         n = 0
         n = -1
         Encountered ArgumentOutOfRangeException: Specified argument was out of the range
          of valid values.
         */

In diesem Beispiel wird der Fall erläutert, in dem eine Ausnahme im Delegaten eines Ausführungsdatenflussblocks unbehandelt bleibt. Es wird empfohlen, Ausnahmen in den Codetexten solcher Blöcke zu behandeln. Wenn dies jedoch nicht möglich ist, verhält sich der Block, als ob er abgebrochen wurde, und verarbeitet keine eingehenden Nachrichten.

Wenn ein Datenflussblock explizit abgebrochen wird die AggregateException Objekt enthält OperationCanceledException in der InnerExceptions Eigenschaft. Weitere Informationen über das Abbrechen von Datenflüssen finden Sie unter "Aktivieren des Abbruchs" weiter unten in diesem Dokument.

Die zweite Möglichkeit, den Abschlussstatus eines Datenflussblocks zu bestimmen, ist die Verwendung einer Fortsetzung außerhalb der Abschlussaufgabe oder die Verwendung der asynchronen Sprachfunktionen von C# und Visual Basic, um auf die Abschlussaufgabe asynchron zu warten. Der Delegat, den Sie zum Bereitstellen der Task.ContinueWith -Methode akzeptiert ein Aufgabe -Objekt, das die vorangehende Aufgabe darstellt. Im Fall von der Abschluss -Eigenschaft nimmt der Delegat für die Fortsetzung die Abschlussaufgabe selbst. Das folgende Beispiel ähnelt das vorherige Beispiel, außer dass auch mithilfe der ContinueWith Methode, um eine Abschlussaufgabe zu erstellen, die den Status des gesamten datenflussvorgangs ausgibt.

         // Create an ActionBlock<int> object that prints its input
         // and throws ArgumentOutOfRangeException if the input
         // is less than zero.
         var throwIfNegative = new ActionBlock<int>(n =>
         {
            Console.WriteLine("n = {0}", n);
            if (n < 0)
            {
               throw new ArgumentOutOfRangeException();
            }
         });

         // Create a continuation task that prints the overall 
         // task status to the console when the block finishes.
         throwIfNegative.Completion.ContinueWith(task =>
         {
            Console.WriteLine("The status of the completion task is '{0}'.", 
               task.Status);
         });

         // Post values to the block.
         throwIfNegative.Post(0);
         throwIfNegative.Post(-1);
         throwIfNegative.Post(1);
         throwIfNegative.Post(-2);
         throwIfNegative.Complete();

         // Wait for completion in a try/catch block.
         try
         {
            throwIfNegative.Completion.Wait();
         }
         catch (AggregateException ae)
         {
            // If an unhandled exception occurs during dataflow processing, all
            // exceptions are propagated through an AggregateException object.
            ae.Handle(e =>
            {
               Console.WriteLine("Encountered {0}: {1}",
                  e.GetType().Name, e.Message);
               return true;
            });
         }

         /* Output:
         n = 0
         n = -1
         The status of the completion task is 'Faulted'.
         Encountered ArgumentOutOfRangeException: Specified argument was out of the range
          of valid values.
         */

Sie können auch Eigenschaften verwenden, z. B. IsCanceled im Hauptteil der Fortsetzungsaufgabe um zusätzliche Informationen über den Abschlussstatus eines datenflussblocks zu bestimmen. Weitere Informationen zu Fortsetzungsaufgaben und deren Beziehung zu Abbruch- und Fehlerbehandlung finden Sie unter Verketten von Aufgaben mithilfe von Fortsetzungsaufgaben, Aufgabenabbruch, Ausnahmebehandlung, und NIB: Gewusst wie: Behandeln Ausnahmen, die von Aufgaben ausgelöste.

[go to top]

Die TPL-Datenflussbibliothek enthält mehrere vordefinierte Datenflussblocktypen. Diese Typen sind in drei Kategorien unterteilt: pufferblöcke, ausführungsblöcke, und gruppierungsblöcke. In den folgenden Abschnitten werden die Blocktypen dieser Kategorien beschrieben.

Pufferblöcke

Pufferblöcke enthalten Daten zur Verwendung durch Datenconsumer. Die TPL-Datenflussbibliothek enthält drei pufferblocktypen: System.Threading.Tasks.Dataflow.BufferBlock<>>, System.Threading.Tasks.Dataflow.BroadcastBlock<>>, und System.Threading.Tasks.Dataflow.WriteOnceBlock<>>.

BufferBlock(T)

Die BufferBlock<> </> > -Klasse stellt eine allgemeine Struktur des asynchronen messaging dar. Diese Klasse speichert eine FIFO-Nachrichtenwarteschlange (First In, First Out), in die mehrere Quellen Nachrichten schreiben oder aus der mehrere Ziele Nachrichten auslesen können. Wenn ein Ziel empfängt eine Nachricht von einer BufferBlock<> </> > -Objekt, wird diese Nachricht aus der Nachrichtenwarteschlange entfernt. Daher zwar ein BufferBlock<> </> > -Objekt mehrere Ziele haben kann, die jede Nachricht von nur einem Ziel empfangen werden. Die BufferBlock<> </> > Klasse ist hilfreich, wenn Sie mehrere Nachrichten an eine andere Komponente übergeben möchten und diese Komponente alle Nachrichten empfangen muss.

Im folgende grundlegende Beispiel stellt mehrere Int32 -Werte in einer BufferBlock<> </> > -Objekt und anschließend wieder aus dem Objekt gelesen.

         // Create a BufferBlock<int> object.
         var bufferBlock = new BufferBlock<int>();
         
         // Post several messages to the block.
         for (int i = 0; i < 3; i++)
         {
            bufferBlock.Post(i);
         }

         // Receive the messages back from the block.
         for (int i = 0; i < 3; i++)
         {
            Console.WriteLine(bufferBlock.Receive());
         }
         
         /* Output:
            0
            1
            2
          */

Ein vollständiges Beispiel, das veranschaulicht, wie Nachrichten schreiben und Lesen von Nachrichten von einer BufferBlock<> </> > Objekt, finden Sie unter Gewusst wie: Schreiben und Lesen von Nachrichten aus einem Dataflow Block.

BroadcastBlock(T)

Die BroadcastBlock<> </> > Klasse ist hilfreich, wenn mehrere Nachrichten an eine andere Komponente übergeben werden müssen, aber diese Komponente nur den letzten Wert benötigt. Diese Klasse ist darüber hinaus auch hilfreich, wenn Sie eine Nachricht an mehreren Komponenten übertragen möchten.

Die folgenden grundlegenden Beispiel Beiträge ein doppelte -Wert in einen BroadcastBlock<> </> > -Objekt und dann gelesen aus dem Objekt mehrmals. Da Werte nicht entzogen werden BroadcastBlock<> </> > Objekte Nachdem sie gelesen wurden, der gleiche Wert steht jedem.

         // Create a BroadcastBlock<double> object.
         var broadcastBlock = new BroadcastBlock<double>(null);

         // Post a message to the block.
         broadcastBlock.Post(Math.PI);

         // Receive the messages back from the block several times.
         for (int i = 0; i < 3; i++)
         {
            Console.WriteLine(broadcastBlock.Receive());
         }

         /* Output:
            3.14159265358979
            3.14159265358979
            3.14159265358979
          */

Ein vollständiges Beispiel, das veranschaulicht, wie Sie BroadcastBlock<> </> > eine Nachricht an mehrere Zielblöcke gesendet wird, finden Sie unter wie: einen Taskplaner in einem Dataflow Block angeben.

WriteOnceBlock(T)

Die WriteOnceBlock<> </> > -Klasse ähnelt der BroadcastBlock<> </> > Klasse, außer dass eine WriteOnceBlock<> </> > -Objekt nur einmal geschrieben werden kann. Können Sie sich vorstellen WriteOnceBlock<> </> > ähnlich wie die C#- Readonly (ReadOnly in Visual Basic)-Schlüsselwort, abgesehen davon, dass ein WriteOnceBlock<> </> > Objekt wird jedoch unveränderlich, nachdem es einen Wert anstatt einer Konstruktion empfängt. Wie die BroadcastBlock<> </> > -Klasse, wenn ein Ziel eine Nachricht empfängt ein WriteOnceBlock<> </> > -Objekt, wird diese Nachricht aus dem Objekt nicht entfernt. Daher empfangen mehrere Ziele eine Kopie der Nachricht. Die WriteOnceBlock<> </> > Klasse ist hilfreich, wenn Sie nur die erste von mehreren Nachrichten weitergeben möchten.

Das folgende grundlegende Beispiel sendet mehrere Zeichenfolge -Werte in einer WriteOnceBlock<> </> > -Objekt und dann der Wert aus diesem Objekt gelesen. Da ein WriteOnceBlock<> </> > Objekt einmal geschrieben werden kann nur nach einem WriteOnceBlock<> </> > -Objekt eine Nachricht empfängt, werden nachfolgende Nachrichten verworfen.

         // Create a WriteOnceBlock<string> object.
         var writeOnceBlock = new WriteOnceBlock<string>(null);

         // Post several messages to the block in parallel. The first 
         // message to be received is written to the block. 
         // Subsequent messages are discarded.
         Parallel.Invoke(
            () => writeOnceBlock.Post("Message 1"),
            () => writeOnceBlock.Post("Message 2"),
            () => writeOnceBlock.Post("Message 3"));

         // Receive the message from the block.
         Console.WriteLine(writeOnceBlock.Receive());

         /* Sample output:
            Message 2
          */

Ein vollständiges Beispiel, das veranschaulicht, wie Sie WriteOnceBlock<> </> > den Wert des ersten Vorgangs empfangen, die beendet wird, finden Sie unter wie: Verknüpfungen für Datenflussblöcke.

Ausführungsblöcke

Ausführungsblöcke rufen einen vom Benutzer bereitgestellten Delegaten für jedes Element empfangener Daten auf. Die TPL-Datenflussbibliothek enthält drei Typen von ausführungsblöcken: ActionBlock<>>, System.Threading.Tasks.Dataflow.TransformBlock<TInput, TOutput>, und System.Threading.Tasks.Dataflow.TransformManyBlock<TInput, TOutput>.</TInput, TOutput> </TInput, TOutput>

ActionBlock(T)

Die ActionBlock<> </> > Klasse ist ein Zielblock, der einen Delegaten aufruft, wenn es Daten empfängt. Stellen Sie sich eine ActionBlock<> </> > Objekt wie ein Delegat, der asynchron ausgeführt wird, wenn Daten verfügbar werden. Der Delegat, den Sie zum Bereitstellen einer ActionBlock<> </> > Objekt kann vom Typ Aktion oder System.Func<TInput, Task>. Bei Verwendung einer ActionBlock<> </> > -Objekt mit Aktion, Verarbeitung jedes Eingabeelements wird als abgeschlossen betrachtet, wenn der Delegat zurückgegeben. Bei Verwendung einer ActionBlock<> </> > -Objekt mit System.Func<TInput, Task>, Verarbeitung jedes Eingabeelements gilt nur dann abgeschlossen, wenn das zurückgegebene Aufgabe -Objekt abgeschlossen ist. Mithilfe dieser beiden Mechanismen können ActionBlock<> </> > für synchrone und asynchrone Verarbeitung jedes Eingabeelements.

Das folgende grundlegende Beispiel sendet mehrere Int32 -Werte in einer ActionBlock<> </> > Objekt. Die ActionBlock<> </> > -Objekt gibt diese Werte in der Konsole aus. Im Beispiel wird der Block dann in den abgeschlossenen Zustand versetzt, und es wird gewartet, bis alle Datenflussaufgaben abgeschlossen sind.

         // Create an ActionBlock<int> object that prints values
         // to the console.
         var actionBlock = new ActionBlock<int>(n => Console.WriteLine(n));

         // Post several messages to the block.
         for (int i = 0; i < 3; i++)
         {
            actionBlock.Post(i * 10);
         }

         // Set the block to the completed state and wait for all 
         // tasks to finish.
         actionBlock.Complete();
         actionBlock.Completion.Wait();

         /* Output:
            0
            10
            20
          */

Vollständige Beispiele für die Verwendung von Delegaten mit der ActionBlock<> </> > Klasse, finden Sie unter Gewusst wie: Ausführen Aktion Wenn ein Datenflussblock Daten empfängt.

TransformBlock(TInput, TOutput)

Die TransformBlock<TInput, TOutput> -Klasse ähnelt der ActionBlock<> </> > Klasse, die sie als Quelle und als Ziel fungiert.</TInput, TOutput> Der Delegat, der Übergabe an eine TransformBlock<TInput, TOutput> -Objekts gibt einen Wert vom Typ TOutput.</TInput, TOutput> Der Delegat, den Sie zum Bereitstellen einer TransformBlock<TInput, TOutput> Objekt kann vom Typ System.Func<TInput, TOutput> oder System.Func<TInput, Task>.</TInput, TOutput> Bei Verwendung einer TransformBlock<TInput, TOutput> -Objekt mit System.Func<TInput, TOutput>, Verarbeitung jedes Eingabeelements wird als abgeschlossen betrachtet, wenn der Delegat zurückgegeben.</TInput, TOutput> Bei Verwendung einer TransformBlock<TInput, TOutput> verwendete Objekt System.Func<TInput, Task<TOutput>>, Verarbeitung jedes Eingabeelements gilt nur dann abgeschlossen, wenn das zurückgegebene Aufgabe -Objekt abgeschlossen ist.</TInput, TOutput> Wie bei ActionBlock<>>, mithilfe dieser beiden Mechanismen können TransformBlock<TInput, TOutput> für synchrone und asynchrone Verarbeitung jedes Eingabeelements.</TInput, TOutput>

Das folgende grundlegende Beispiel erstellt eine TransformBlock<TInput, TOutput> -Objekt, das die Quadratwurzel der Eingabe berechnet.</TInput, TOutput> Die TransformBlock<TInput, TOutput> -Objekt nimmt Int32 -Werte als Eingabe und erzeugt doppelte -Werte als Ausgabe.</TInput, TOutput>

         // Create a TransformBlock<int, double> object that 
         // computes the square root of its input.
         var transformBlock = new TransformBlock<int, double>(n => Math.Sqrt(n));

         // Post several messages to the block.
         transformBlock.Post(10);
         transformBlock.Post(20);
         transformBlock.Post(30);

         // Read the output messages from the block.
         for (int i = 0; i < 3; i++)
         {
            Console.WriteLine(transformBlock.Receive());
         }

         /* Output:
            3.16227766016838
            4.47213595499958
            5.47722557505166
          */

Vollständige Beispiele für die Verwendung TransformBlock<TInput, TOutput> in einem Netzwerk von Datenflussblöcken, Image-Verarbeitung in einer Windows Forms-Anwendung ausführt, finden Sie unter Exemplarische Vorgehensweise: Datenfluss in einer Windows Forms-Anwendung.</TInput, TOutput>

TransformManyBlock(TInput, TOutput)

Die TransformManyBlock<TInput, TOutput> -Klasse ähnelt der TransformBlock<TInput, TOutput> Klasse, außer dass TransformManyBlock<TInput, TOutput> NULL oder mehr Ausgabewerte erzeugt, für jeden Eingabewert, anstatt nur eines für jeden Eingabewert Ausgabewerts.</TInput, TOutput> </TInput, TOutput> </TInput, TOutput> Der Delegat, den Sie zum Bereitstellen einer TransformManyBlock<TInput, TOutput> Objekt kann vom Typ System.Func<TInput, IEnumerable<TOutput>> oder type System.Func<TInput, Task<IEnumerable<TOutput>>>.</TInput, TOutput> Bei Verwendung einer TransformManyBlock<TInput, TOutput> -Objekt mit System.Func<TInput, IEnumerable<TOutput>>, Verarbeitung jedes Eingabeelements wird als abgeschlossen betrachtet, wenn der Delegat zurückgegeben.</TInput, TOutput> Bei Verwendung einer TransformManyBlock<TInput, TOutput> -Objekt mit System.Func<TInput, Task<IEnumerable<TOutput>>>, Verarbeitung jedes Eingabeelements gilt nur dann abgeschlossen, wenn das zurückgegebene System.Threading.Tasks.Task<IEnumerable<TOutput>> -Objekt abgeschlossen ist.</TInput, TOutput>

Das folgende grundlegende Beispiel erstellt eine TransformManyBlock<TInput, TOutput> -Objekt, das Zeichenfolgen in ihre einzelnen Zeichensequenzen aufteilt.</TInput, TOutput> Die TransformManyBlock<TInput, TOutput> -Objekt nimmt Zeichenfolge -Werte als Eingabe und erzeugt Char -Werte als Ausgabe.</TInput, TOutput>

         // Create a TransformManyBlock<string, char> object that splits
         // a string into its individual characters.
         var transformManyBlock = new TransformManyBlock<string, char>(
            s => s.ToCharArray());

         // Post two messages to the first block.
         transformManyBlock.Post("Hello");
         transformManyBlock.Post("World");

         // Receive all output values from the block.
         for (int i = 0; i < ("Hello" + "World").Length; i++)
         {
            Console.WriteLine(transformManyBlock.Receive());
         }

         /* Output:
            H
            e
            l
            l
            o
            W
            o
            r
            l
            d
          */

Vollständige Beispiele für die Verwendung TransformManyBlock<TInput, TOutput> mehrere unabhängige Ausgaben für jede Eingabe in einer Datenflusspipeline erzeugt werden, finden Sie unter Exemplarische Vorgehensweise: Erstellen einer Datenflusspipeline.</TInput, TOutput>

Grad der Parallelität

Jede ActionBlock<>>, TransformBlock<TInput, TOutput>, und TransformManyBlock<TInput, TOutput> -Objekt puffert eingehende Nachrichten, bis der Block bereit für die Verarbeitung ist.</TInput, TOutput> </TInput, TOutput> In der Standardeinstellung verarbeiten diese Klassen Nachrichten nacheinander in der Reihenfolge, in der sie empfangen werden. Sie können auch angeben, den Grad der Parallelität zu ActionBlock<>>, TransformBlock<TInput, TOutput> und TransformManyBlock<TInput, TOutput> -Objekte mehrere Nachrichten gleichzeitig verarbeiten.</TInput, TOutput> </TInput, TOutput> Weitere Informationen über die gleichzeitige Ausführung finden Sie im Abschnitt "Festlegen des Grads der Parallelität" weiter unten in diesem Dokument. Ein Beispiel, den Grad der Parallelität so ein ausführungsdatenflussblock mehrere Nachrichten gleichzeitig verarbeiten kann, finden Sie unter Gewusst wie: Festlegen des Grads der Parallelität in einem Dataflow Block.

Übersicht über Delegattypen

Der folgenden Tabelle sind die Delegattypen, die Sie bereitstellen können ActionBlock<>>, TransformBlock<TInput, TOutput>, und TransformManyBlock<TInput, TOutput> Objekte.</TInput, TOutput> </TInput, TOutput> In dieser Tabelle wird auch angegeben, ob der Delegattyp synchron oder asynchron arbeitet.

TypSynchroner DelegattypAsynchroner Delegattyp
ActionBlock<>>System.ActionSystem.Func<TInput, Task>
TransformBlock<TInput, TOutput></TInput, TOutput>System.Func<TInput, TOutput>2`System.Func<TInput, Task<TOutput>>
TransformManyBlock<TInput, TOutput></TInput, TOutput>System.Func<TInput, IEnumerable<TOutput>>System.Func<TInput, Task<IEnumerable<TOutput>>>

Sie können auch Lambda-Ausdrücke verwenden, wenn Sie mit Ausführungsblocktypen arbeiten. Ein Beispiel, das zeigt, wie Sie einen Lambda-Ausdruck mit einem Ausführungsblock finden Sie unter Gewusst wie: Ausführen Aktion Wenn ein Datenflussblock Daten empfängt.

Gruppierungsblöcke

Gruppierungsblöcke kombinieren Daten aus einer oder mehreren Quellen und unter verschiedenen Einschränkungen. Die TPL-Datenflussbibliothek enthält drei Typen von gruppierungsblöcken: BatchBlock<>>, JoinBlock<T1, T2>, und BatchedJoinBlock<T1, T2>.</T1, T2> </T1, T2>

BatchBlock(T)

Die BatchBlock<> </> > -Klasse kombiniert Sätze von Eingabedaten, die als Batches, in Arrays von Ausgabedaten bezeichnet werden. Beim Erstellen, geben Sie die Größe von jedem Batch eine BatchBlock<> </> > Objekt. Wenn die BatchBlock<> </> > -Objekt die angegebene Anzahl von Eingabeelementen empfängt, wird asynchron Eingabeelementen ein Array, das die Elemente enthält. Wenn ein BatchBlock<> </> > -Objekt enthält nicht genügend Elemente zum Bilden eines Batches jedoch auf den abgeschlossenen Zustand Eingabeelementen, wird ein abschließendes Array, das die restlichen Eingabeelementen enthält.

Die BatchBlock<> </> > -Klasse arbeitet entweder im gierige oder nicht gierige Modus. Im gierigen Modus, der Standardwert ist, eine BatchBlock<> </> > Objekt akzeptiert jede Nachricht, dass es angeboten wird, und gibt ein Array weiter, nachdem es die angegebene Anzahl von Elementen empfangen. Im nicht gierigen Modus eine BatchBlock<> </> > -Objekt alle eingehenden Nachrichten zurück, bis genügend Quellen, Nachrichten an den Block angeboten wurden, um einen Batch zu bilden. Der gierige Modus erzielt in der Regel eine bessere Leistung als der nicht gierige Modus, da er weniger Verarbeitungsaufwand erfordert. Sie können den nicht gierigen Modus jedoch verwenden, wenn Sie die Nutzung von mehreren Quellen auf atomische Weise koordinieren müssen. Nicht gierigen Modus angeben, indem gierige auf False in der dataflowBlockOptions -Parameter in der BatchBlock<> </> > Konstruktor.

Im folgende grundlegende Beispiel stellt mehrere Int32 -Werte in einer BatchBlock<> </> > -Objekt, das zehn Elemente in einem Batch enthält. Um sicherzustellen, dass alle Werte von weitergeben der BatchBlock<>>, dieses Beispiel ruft die abgeschlossen Methode. Die vollständig -Methode legt die BatchBlock<> </> > Objekt in den abgeschlossenen Zustand, und daher die BatchBlock<> </> > -Objekt alle verbleibenden Elemente einem abschließenden Batch weitergegeben.

         // Create a BatchBlock<int> object that holds ten
         // elements per batch.
         var batchBlock = new BatchBlock<int>(10);

         // Post several values to the block.
         for (int i = 0; i < 13; i++)
         {
            batchBlock.Post(i);
         }
         // Set the block to the completed state. This causes
         // the block to propagate out any any remaining
         // values as a final batch.
         batchBlock.Complete();

         // Print the sum of both batches.

         Console.WriteLine("The sum of the elements in batch 1 is {0}.",
            batchBlock.Receive().Sum());

         Console.WriteLine("The sum of the elements in batch 2 is {0}.",
            batchBlock.Receive().Sum());

         /* Output:
            The sum of the elements in batch 1 is 45.
            The sum of the elements in batch 2 is 33.
          */

Ein vollständiges Beispiel, das verwendet BatchBlock<> </> > zur Verbesserung der Effizienz von datenbankeinfügevorgängen finden Sie unter Exemplarische Vorgehensweise: Verwendung von BatchBlock und BatchedJoinBlock Effizienz verbessern.

JoinBlock(T1, T2, ...)

Die JoinBlock<T1, T2> und JoinBlock<T1, T2, T3> Klassen sammeln Eingabeelemente und weiterzugeben System.Tuple<T1, T2> oder System.Tuple<T1, T2, T3> Objekte, die diese Elemente enthalten.</T1, T2, T3> </T1, T2> </T1, T2, T3> </T1, T2> Die JoinBlock<T1, T2> und JoinBlock<T1, T2, T3> Klassen erben nicht von ITargetBlock<>>.</T1, T2, T3> </T1, T2> Stattdessen verfügen sie über Eigenschaften, ziel1, Target2, und Target3, implementieren ITargetBlock<>>.

Wie BatchBlock<>>, JoinBlock<T1, T2> und JoinBlock<T1, T2, T3> im gierigen oder im nicht gierigen Modus ausgeführt werden.</T1, T2, T3> </T1, T2> Im gierigen Modus, der Standardwert ist, eine JoinBlock<T1, T2> oder JoinBlock<T1, T2, T3> Objekt akzeptiert jede Nachricht, dass es angeboten wird, und gibt ein Tupel weiter, nachdem jedes der zugehörigen Ziele mindestens eine Nachricht empfängt.</T1, T2, T3> </T1, T2> Im nicht gierigen Modus eine JoinBlock<T1, T2> oder JoinBlock<T1, T2, T3> -Objekt alle eingehende Nachrichten zurückstellt, bis allen Zielen die Daten angeboten wurden, die zum Erstellen eines Tupels erforderlich sind.</T1, T2, T3> </T1, T2> An diesem Punkt initiiert der Block ein Zweiphasencommit-Protokoll, um alle erforderlichen Elemente aus den Quellen atomar abzurufen. Durch diese Zurückstellung ist es möglich, dass eine andere Entität die Daten in der Zwischenzeit nutzt, sodass das gesamte System mit der Verarbeitung fortschreitet.

Das folgende grundlegende Beispiel zeigt einen Fall, in dem ein JoinBlock<T1, T2, T3> -Objekt mehrere Daten benötigt, einen Wert zu berechnen.</T1, T2, T3> In diesem Beispiel wird ein JoinBlock<T1, T2, T3> -Objekt, das zwei erfordert Int32 Werte und ein Char Wert, der eine arithmetische Operation durchzuführen.</T1, T2, T3>

         // Create a JoinBlock<int, int, char> object that requires
         // two numbers and an operator.
         var joinBlock = new JoinBlock<int, int, char>();

         // Post two values to each target of the join.

         joinBlock.Target1.Post(3);
         joinBlock.Target1.Post(6);

         joinBlock.Target2.Post(5);
         joinBlock.Target2.Post(4);

         joinBlock.Target3.Post('+');
         joinBlock.Target3.Post('-');

         // Receive each group of values and apply the operator part
         // to the number parts.

         for (int i = 0; i < 2; i++)
         {
            var data = joinBlock.Receive();
            switch (data.Item3)
            {
               case '+':
                  Console.WriteLine("{0} + {1} = {2}",
                     data.Item1, data.Item2, data.Item1 + data.Item2);
                  break;
               case '-':
                  Console.WriteLine("{0} - {1} = {2}",
                     data.Item1, data.Item2, data.Item1 - data.Item2);
                  break;
               default:
                  Console.WriteLine("Unknown operator '{0}'.", data.Item3);
                  break;
            }
         }

         /* Output:
            3 + 5 = 8
            6 - 4 = 2
          */

Ein vollständiges Beispiel, das verwendet JoinBlock<T1, T2> Objekte im nicht gierigen Modus zur kooperativen Nutzung einer Ressource finden Sie unter wie: JoinBlock zum Lesen aus mehreren Quellen.</T1, T2>

BatchedJoinBlock(T1, T2, ...)

Die BatchedJoinBlock<T1, T2> und BatchedJoinBlock<T1, T2, T3> -Klasse sammeln Batches von Eingabeelementen und weitergeben System.Tuple(IList(T1), IList(T2)) oder System.Tuple(IList(T1), IList(T2), IList(T3)) -Objekten, die diese Elemente enthalten.</T1, T2, T3> </T1, T2> Stellen Sie sich BatchedJoinBlock<T1, T2> als Kombination aus BatchBlock<> </> > und JoinBlock<T1, T2>.</T1, T2> </T1, T2> Geben Sie die Größe von jedem Batch, bei der Erstellung einer BatchedJoinBlock<T1, T2> Objekt.</T1, T2> BatchedJoinBlock<T1, T2> verfügt auch über Eigenschaften, ziel1 und Target2, implementieren ITargetBlock<>>.</T1, T2> Wenn die angegebene Anzahl von Eingabeelementen werden von allen Zielen empfangen die BatchedJoinBlock<T1, T2> -Objekt asynchron weitergegeben ein System.Tuple(IList(T1), IList(T2)) -Objekt, das die Elemente enthält.</T1, T2>

Das folgende grundlegende Beispiel erstellt eine BatchedJoinBlock<T1, T2> -Objekt, das Ergebnisse enthält Int32 Werten und den Fehlern, die Ausnahme Objekte.</T1, T2> In diesem Beispiel werden mehrere Vorgänge durchgeführt, und schreibt die Ergebnisse in der Target1 -Eigenschaft und Fehler in der Target2 -Eigenschaft, der die BatchedJoinBlock<T1, T2> Objekt.</T1, T2> Da die Anzahl der erfolgreichen und fehlgeschlagenen Vorgänge im Voraus unbekannt ist die IList<> </> > -Objekte ermöglichen, dass jedes Ziel NULL oder mehr Werte empfängt.

         // For demonstration, create a Func<int, int> that 
         // returns its argument, or throws ArgumentOutOfRangeException
         // if the argument is less than zero.
         Func<int, int> DoWork = n =>
         {
            if (n < 0)
               throw new ArgumentOutOfRangeException();
            return n;
         };

         // Create a BatchedJoinBlock<int, Exception> object that holds 
         // seven elements per batch.
         var batchedJoinBlock = new BatchedJoinBlock<int, Exception>(7);

         // Post several items to the block.
         foreach (int i in new int[] { 5, 6, -7, -22, 13, 55, 0 })
         {
            try
            {
               // Post the result of the worker to the 
               // first target of the block.
               batchedJoinBlock.Target1.Post(DoWork(i));
            }
            catch (ArgumentOutOfRangeException e) 
            {
               // If an error occurred, post the Exception to the 
               // second target of the block.
               batchedJoinBlock.Target2.Post(e); 
            }
         }
        
         // Read the results from the block.
         var results = batchedJoinBlock.Receive();

         // Print the results to the console.

         // Print the results.
         foreach (int n in results.Item1)
         {
            Console.WriteLine(n);
         }
         // Print failures.
         foreach (Exception e in results.Item2)
         {
            Console.WriteLine(e.Message);
         }

         /* Output:
            5
            6
            13
            55
            0
            Specified argument was out of the range of valid values.
            Specified argument was out of the range of valid values.
          */

Ein vollständiges Beispiel, das verwendet BatchedJoinBlock<T1, T2> zum Erfassen der Ergebnisse und Ausnahmen, die auftreten, während das Programm aus einer Datenbank liest, finden Sie unter Exemplarische Vorgehensweise: Verwendung von BatchBlock und BatchedJoinBlock Effizienz verbessern.</T1, T2>

[go to top]

Sie können zusätzliche Optionen aktivieren, durch die Bereitstellung einer System.Threading.Tasks.Dataflow.DataflowBlockOptions -Objekt an den Konstruktor von datenflussblocktypen. Diese Optionen steuern das Verhalten wie z. B. den Planer, der die zugrunde liegende Aufgabe und den Grad der Parallelität verwaltet. Die DataflowBlockOptions verfügt außerdem über abgeleitete Typen, die Verhalten anzugeben, die für bestimmte datenflussblocktypen spezifisch ist. In der folgenden Tabelle ist zusammengefasst, welcher Optionstyp den einzelnen Datenflussblocktypen zugeordnet ist.

DatenflussblocktypDataflowBlockOptions Typ
BufferBlock<>>DataflowBlockOptions
BroadcastBlock<>>DataflowBlockOptions
WriteOnceBlock<>>DataflowBlockOptions
ActionBlock<>>ExecutionDataflowBlockOptions
TransformBlock<TInput, TOutput></TInput, TOutput>ExecutionDataflowBlockOptions
TransformManyBlock<TInput, TOutput></TInput, TOutput>ExecutionDataflowBlockOptions
BatchBlock<>>GroupingDataflowBlockOptions
JoinBlock<T1, T2></T1, T2>GroupingDataflowBlockOptions
BatchedJoinBlock<T1, T2></T1, T2>GroupingDataflowBlockOptions

Die folgenden Abschnitte enthalten zusätzliche Informationen über die wichtigen Arten von Datenfluss über die verfügbaren Optionen der System.Threading.Tasks.Dataflow.DataflowBlockOptions, System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions, und System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions Klassen.

Festlegen des Aufgabenplaners

Jeder vordefinierte Datenflussblock verwendet den TPL-Aufgabenplanungsmechanismus zum Durchführen von Aktivitäten, wie das Weitergeben von Daten an ein Ziel, das Empfangen von Daten aus einer Quelle und das Ausführen benutzerdefinierter Delegate, wenn Daten verfügbar werden. TaskScheduler ist eine abstrakte Klasse, die einen Aufgabenplaner darstellt, die Aufgaben in Warteschlangen. Der standardmäßige Taskplaner Standard, verwendet die ThreadPool -Klasse in die Warteschlange und Ausführen der Arbeitsaufgabe. Sie können den Standardtaskplaner überschreiben, indem die TaskScheduler Eigenschaft, wenn Sie ein datenflussblockobjekt erstellen.

Wenn der gleiche Aufgabenplaner mehrere Datenflussblöcke verwaltet, kann er Richtlinien für sie erzwingen. Wenn mehrere Datenflussblöcke jeweils den exklusiven Planer des gleichen Ziel konfiguriert beispielsweise ConcurrentExclusiveSchedulerPair -Objekt, die gesamte Arbeit, die auf diesen Blöcken ausgeführt wird, serialisiert wird. Auch wenn diese Blöcke den parallele Planer des gleichen Ziel konfiguriert ConcurrentExclusiveSchedulerPair -Objekt, und dieser Planer eine maximale nebenläufigkeitsebene konfiguriert ist, alle Arbeit von diesen Blöcken auf diese Anzahl gleichzeitiger Vorgänge beschränkt ist. Ein Beispiel für die Verwendung der ConcurrentExclusiveSchedulerPair -Klasse Lesevorgänge parallel, Schreibvorgänge jedoch exklusiv von allen anderen Vorgängen erfolgen, finden Sie unter wie: einen Taskplaner in einem Dataflow Block angeben. Weitere Informationen zum Aufgabenplaner in der TPL finden Sie unter der TaskScheduler Thema-Klasse.

Festlegen des Grads der Parallelität

Standardmäßig werden die drei ausführungsblocktypen, die die TPL-Datenflussbibliothek bereitstellt, ActionBlock<>>, TransformBlock<TInput, TOutput>, und TransformManyBlock<TInput, TOutput>, mehrere Nachrichten gleichzeitig verarbeitet.</TInput, TOutput> </TInput, TOutput> Diese Datenflussblocktypen verarbeiten Nachrichten ebenfalls in der Reihenfolge, in der sie empfangen werden. Um diese Datenflussblöcke Nachrichten gleichzeitig verarbeiten zu aktivieren, legen Sie die ExecutionDataflowBlockOptions.MaxDegreeOfParallelism -Eigenschaft beim Erstellen des datenflussblockobjekts.

Der Standardwert von MaxDegreeOfParallelism ist 1. Dadurch wird sichergestellt, dass der Datenflussblock mehrere Nachrichten gleichzeitig verarbeitet. Durch das Festlegen dieser Eigenschaft auf einen Wert, der größer als 1 ist, kann der Datenflussblock mehrere Nachrichten gleichzeitig verarbeiten. Wenn diese Eigenschaft auf DataflowBlockOptions.Unbounded kann die zugrunde liegende Aufgabenplaner den maximalen Grad an Parallelität zu verwalten.

System_CAPS_ICON_important.jpg Wichtig

Wenn Sie einen maximalen Grad an Parallelität angeben, der größer als 1 ist, werden mehrere Nachrichten gleichzeitig verarbeitet. Daher werden Nachrichten möglicherweise nicht in der Reihenfolge verarbeitet, in der sie empfangen werden. Die Reihenfolge, in der die Nachrichten vom Blocks ausgegeben werden, ist jedoch ordnungsgemäß sortiert.

Da die MaxDegreeOfParallelism -Eigenschaft den maximalen Grad an Parallelität darstellt, wird der Datenflussblock möglicherweise mit einem geringeren Grad an Parallelität ausgeführt, als Sie angeben. Der Datenflussblock kann zum Erfüllen seiner Funktionsanforderungen oder aufgrund eines Mangels an verfügbaren Systemressourcen einen geringeren Grad an Parallelität verwenden. Ein Datenflussblock wird nie mit mehr Parallelität ausgeführt als Sie angeben.

Der Wert der MaxDegreeOfParallelism -Eigenschaft ist exklusiv für jedes datenflussblockobjekt. Wenn beispielsweise für vier Datenflussblockobjekte als maximaler Grad an Parallelität jeweils 1 angegeben wird, können u. U. alle vier Datenflussblockobjekte parallel ausgeführt werden.

Ein Beispiel, den maximalen Grad an Parallelität für lang andauernde Operationen parallel auftreten können, finden Sie unter Gewusst wie: Angeben des Grads der Parallelität in einem Dataflow Block.

Festlegen der Anzahl von Nachrichten pro Aufgabe

Die vordefinierten Datenflussblocktypen verwenden Aufgaben, um mehrere Eingabeelemente zu verarbeiten. Dadurch kann die Anzahl der zum Verarbeiten von Daten erforderlichen Aufgabenobjekte minimiert werden, sodass Anwendungen effizienter ausgeführt werden können. Wenn Daten von den Aufgaben aus einem Satz von Datenflussblöcken verarbeitet werden, müssen die Aufgaben von anderen Datenflussblöcken jedoch möglicherweise auf Verarbeitungszeit warten, indem Nachrichten in die Warteschlange gestellt werden. Um eine bessere Ausgewogenheit zwischen datenflussaufgaben zu aktivieren, legen Sie die MaxMessagesPerTask Eigenschaft. Wenn MaxMessagesPerTask Wert DataflowBlockOptions.Unbounded, dies ist die Standardeinstellung, die von einem Datenflussblock verwendete Aufgabe verarbeitet alle Nachrichten verfügbar sind. Wenn MaxMessagesPerTask festgelegt ist auf einen anderen Wert als Unbounded, der Datenflussblock verarbeitet höchstens diese Anzahl an Nachrichten pro Aufgabe Objekt. Obwohl durch das Festlegen der MaxMessagesPerTask Eigenschaft Fairness zwischen Aufgaben erhöhen kann, wird das System mehr Aufgaben als nötig, erstellen die Leistung abnehmen kann.

Aktivieren des Abbruchs

Die TPL bietet einen Mechanismus, durch den Aufgaben Abbrüche kooperative koordinieren können. Legen Sie zum Aktivieren der Datenflussblöcke diesen Abbruchmechanismus nutzen die CancellationToken Eigenschaft. Wenn dies CancellationToken Objekt in den abgebrochenen Zustand, alle Datenflussblöcke, die dieses Token überwachen beendet die Ausführung ihres aktuellen Elements, jedoch Verarbeitung nachfolgender Elemente nicht starten. Diese Datenflussblöcke löschen außerdem alle gepufferten Nachrichten, geben Verbindungen zu allen Quell- und Zielblöcken frei und wechseln in den abgebrochenen Zustand. Durch den Übergang in den abgebrochenen Zustand, der Abschluss Eigenschaft verfügt über die Status Eigenschaft festgelegt, um Canceled, wenn eine Ausnahme während der Verarbeitung aufgetreten ist. In diesem Fall Status Wert Faulted.

Ein Beispiel für die Verwendung von Abbrüchen in einer Windows Forms-Anwendung, finden Sie unter Gewusst wie: Abbrechen einer Dataflow-Block. Weitere Informationen über Abbrüche in der TPL finden Sie unter Aufgabenabbruch.

Festlegen von gierigem Verhalten im Vergleich zu nicht gierigem Verhalten

Mehrere gruppierungsdatenflussblocktypen können entweder in Betrieb gierige oder nicht gierige Modus. In der Standardeinstellung arbeiten die vordefinierten Datenflussblocktypen im gierigen Modus.

Blockieren Sie für einen Join Typen wie z. B. JoinBlock<T1, T2>, bedeutet der gierige Modus, dass Daten vom Block sofort angenommen, auch wenn die entsprechenden Daten mit den join noch nicht verfügbar ist.</T1, T2> Nicht gieriger Modus bedeutet, dass der Block alle eingehenden Nachrichten zurückstellt, bis eine Nachricht an jedem der zugehörigen Ziele verfügbar ist, um die Gruppierung zu vervollständigen. Wenn eine der zurückgestellten Nachrichten nicht mehr verfügbar ist, gibt der Gruppierungsblock alle zurückgestellten Nachrichten frei und startet den Prozess neu. Für die BatchBlock<> </> > -Klasse ist das gierige und nicht gierige Verhalten ähnlich, außer dass im nicht gierigen Modus ist ein BatchBlock<> </> > -Objekt alle eingehenden Nachrichten zurück, bis genügend verfügbare aus verschiedenen Quellen, um einen Batch zu vervollständigen.

Um nicht gierigen Modus für einen Datenflussblock anzugeben, legen Sie gierige auf False. Ein Beispiel für die Verwendung nicht gierigen Modus mehrere gruppierungsblöcke eine Datenquelle effizienter gemeinsam verwenden können, finden Sie unter wie: JoinBlock zum Lesen aus mehreren Quellen.

[go to top]

Obwohl die TPL-Datenflussbibliothek viele vordefinierte Blocktypen bereitstellt, können Sie zusätzliche Blockstypen mit einem benutzerdefinierten Verhalten erstellen. Implementieren der ISourceBlock<> </> > oder ITargetBlock<> </> > Schnittstellen direkt, oder verwenden Sie die kapseln<TInput, TOutput> Methode, um einen komplexen Block zu erstellen, die das Verhalten vorhandener Blocktypen kapselt.</TInput, TOutput> Beispiele zur Verwendung benutzerdefinierter datenflussblockfunktionen finden Sie unter Exemplarische Vorgehensweise: Erstellen einer benutzerdefinierten Datenflussblocktyp.

[go to top]

TitelBeschreibung
Gewusst wie: Schreiben und Lesen von Nachrichten aus einem DatenflussblockVeranschaulicht das Schreiben und Lesen von Nachrichten aus einer BufferBlock<> </> > Objekt.
Gewusst wie: Implementieren eines Producer-Consumer-MustersBeschreibt, wie mit dem Datenflussmodell ein Producer-Consumer-Muster implementiert wird, bei dem der Producer Nachrichten an einen Datenflussblock sendet und der Consumer Nachrichten aus diesem Block liest.
Gewusst wie: Aktion ausführen, wenn ein Datenflussblock Daten empfängt.Beschreibt das Bereitstellen von Delegaten, die ausführungsdatenflussblocktypen ActionBlock<>>, TransformBlock<TInput, TOutput>, und TransformManyBlock<TInput, TOutput>.</TInput, TOutput> </TInput, TOutput>
Exemplarische Vorgehensweise: Erstellen einer DatenflusspipelineBeschreibt, wie eine Datenflusspipeline erstellt wird, die Text aus dem Web herunterlädt und Vorgänge für diesen Text ausführt.
Gewusst wie: Verknüpfungen für Datenflussblöcke aufhebenVeranschaulicht, wie die VerknüpfungMit Methode, um einem Zielblock und der zugehörigen Quelle aufheben, nachdem die Quelle dem Ziel eine Nachricht anbietet.
Exemplarische Vorgehensweise: Datenfluss in einer Windows Forms-Anwendung verwendenVeranschaulicht, wie ein Netzwerk von Datenflussblöcken erstellt wird, die eine Bildverarbeitung in einer Windows Forms-Anwendung durchführen.
Gewusst wie: einen Datenflussblock AbbrechenVeranschaulicht die Verwendung von Abbrüchen in einer Windows Forms-Anwendung.
Gewusst wie: JoinBlock zum Lesen von Daten aus mehreren Quellen verwendenErläutert, wie die JoinBlock<T1, T2> Klasse, um einen Vorgang auszuführen, wenn Daten verfügbar, aus mehreren Quellen und zum nicht gierigen Modus verwenden sind, um mehrere gruppierungsblöcke eine Datenquelle effizienter gemeinsam verwenden können.</T1, T2>
Gewusst wie: angeben den Grad der Parallelität in einem DatenflussblockBeschreibt das Festlegen der MaxDegreeOfParallelism -Eigenschaft können Sie ein ausführungsdatenflussblock mehrere Nachrichten gleichzeitig verarbeiten zu aktivieren.
Gewusst wie: einen Taskplaner in einem Datenflussblock angebenVeranschaulicht, wie ein bestimmter Aufgabenplaner zugeordnet wird, wenn Sie Datenfluss in Ihrer Anwendung verwenden.
Exemplarische Vorgehensweise: Verwendung von BatchBlock und BatchedJoinBlock zur Verbesserung der EffizienzBeschreibt, wie die BatchBlock<> </> > Klasse steigert die Effizienz der Datenbank einfügen, Operationen und zum Verwenden der BatchedJoinBlock<T1, T2> Klasse zum Erfassen der Ergebnisse und Ausnahmen, die auftreten, während das Programm aus einer Datenbank liest.</T1, T2>
Exemplarische Vorgehensweise: Erstellen eines Datenflussblock-TypsVeranschaulicht zwei Möglichkeiten, einen Datenflussblocktyp zu erstellen, der benutzerdefiniertes Verhalten implementiert.
Task Parallel Library (TPL)Stellt die TPL vor, eine Bibliothek, die die parallele Programmierung in .NET Framework-Anwendungen vereinfacht.
Anzeigen: