Flusso di dati (Task Parallel Library)

.NET Framework (current version)
 

Data di pubblicazione: ottobre 2016

Task Parallel Library (TPL) fornisce componenti del flusso di dati per aumentare l'affidabilità delle applicazioni abilitate per la concorrenza. Questi componenti sono collettivamente il flussi di dati TPL. Con questo modello del flusso di dati viene promossa la programmazione basata su attori fornendo il passaggio di messaggi in-process per attività di pipelining e per un flusso di dati con granularità grossolana. I componenti del flusso di dati sono basati sui tipi e sull'infrastruttura di pianificazione della libreria TPL e si integrano con il supporto dei linguaggi C#, Visual Basic e F# per la programmazione asincrona. Questi componenti sono utili qualora siano presenti più operazioni che devono comunicare tra loro in modo asincrono o qualora si desideri elaborare i dati non appena diventano disponibili. Si consideri, ad esempio, un'applicazione tramite cui vengono elaborati i dati immagine di una webcam. Tramite il modello del flusso di dati, l'applicazione è in grado di elaborare i fotogrammi delle immagini quando diventano disponibili. Se l'applicazione vengono migliorati i fotogrammi dell'immagine, ad esempio, eseguendo la riduzione occhi rossi o correzione chiara, è possibile creare un pipeline dei componenti del flusso di dati. In ogni fase della pipeline è possibile utilizzare la funzionalità di parallelismo con maggiore granulosità grossolana, ad esempio la funzionalità fornita dalla libreria TPL, per trasformare l'immagine.

In questo documento viene fornita una panoramica della libreria del flusso di dati TPL. Vengono descritti il modello di programmazione e i tipi di blocchi di flussi di dati predefiniti e viene indicato come configurare i blocchi di flussi di dati per soddisfare specifici requisiti delle applicazioni.

System_CAPS_ICON_tip.jpg Suggerimento

La libreria del flusso di dati TPL (System.Threading.Tasks.Dataflow dello spazio dei nomi) non viene distribuita con il .NET Framework 4.5. Per installare il System.Threading.Tasks.Dataflow spazio dei nomi, aprire il progetto in Visual Studio 2012, scegliere Gestisci pacchetti NuGet dal menu progetto e cercare online il Microsoft.Tpl.Dataflow pacchetto.

Questo documento contiene le seguenti sezioni:

La libreria del flusso di dati TPL fornisce una base per il passaggio dei messaggi e per la parallelizzazione delle applicazioni con utilizzo intensivo di I/O e di CPU con velocità effettiva elevata e bassa latenza. Offre inoltre un controllo esplicito sul modo in cui i dati vengono memorizzati nel buffer e spostati nel sistema. Per comprendere meglio il modello di programmazione del flusso di dati, si consideri un'applicazione tramite cui vengono caricate in modo asincrono le immagini dal disco e viene creata una composizione di queste immagini. Per i modelli di programmazione tradizionali viene in genere richiesto l'utilizzo di callback e oggetti di sincronizzazione, ad esempio blocchi, per coordinare le attività e accedere ai dati condivisi. Tramite il modello di programmazione del flusso di dati è possibile creare oggetti del flusso di dati mediante i quali vengono elaborate le immagini mentre sono lette dal disco. Nel modello del flusso di dati è possibile dichiarare la modalità di gestione dei dati quando disponibili, nonché tutte le dipendenze tra i dati. Poiché le dipendenze tra i dati sono gestite dal runtime, è spesso possibile evitare la necessità di sincronizzare l'accesso ai dati condivisi. Inoltre, dal momento che tramite il runtime il lavoro viene pianificato in base all'arrivo asincrono di dati, con il flusso di dati è possibile migliorare la velocità di risposta e la velocità effettiva gestendo i thread sottostanti in modo efficiente. Per un esempio che utilizza il modello di programmazione del flusso di dati per implementare l'elaborazione di immagini in un'applicazione Windows Form, vedere procedura dettagliata: utilizzo flussi di dati in un'applicazione Windows Form.

Origini e destinazioni

La libreria del flusso di dati TPL è costituito da blocchi di flussi di dati, vale a dire dati strutture dati buffer ed elaborati. La libreria TPL vengono definiti tre tipi di blocchi di flussi di dati: blocchi di origine, i blocchi di destinazione, e blocchi di propagazione. Un blocco di origine viene utilizzato come origine di dati da cui è possibile leggere. Un blocco di destinazione viene utilizzato come destinatario di dati in cui è possibile scrivere. Un blocco di propagazione viene utilizzato sia come blocco di origine sia come blocco di destinazione, quindi da cui è possibile leggere e in cui è possibile scrivere. La libreria TPL vengono definiti il System.Threading.Tasks.Dataflow.ISourceBlock<> </> > interfaccia per rappresentare le origini, System.Threading.Tasks.Dataflow.ITargetBlock<> </> > per rappresentare le destinazioni e System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput, TOutput> per rappresentare le propagazioni.</TInput, TOutput> IPropagatorBlock<TInput, TOutput> eredita sia da ISourceBlock<>>, e ITargetBlock<>>.</TInput, TOutput>

La libreria di flussi di dati TPL fornisce vari tipi di blocchi di flussi di dati predefiniti che implementano il ISourceBlock<>>, ITargetBlock<>>, e IPropagatorBlock<TInput, TOutput> interfacce.</TInput, TOutput> Questi tipi di blocchi di flussi di dati sono descritti in questo documento nella sezione tipi di blocchi del flusso di dati predefiniti.

Connessione di blocchi

È possibile connettere blocchi di flussi di dati in formato pipeline, che sono sequenze lineari di blocchi di flussi di dati, o reti, che sono grafici di blocchi di flussi di dati. Una pipeline è un tipo di rete. I dati di origini in una pipeline o in una rete vengono propagati nelle destinazioni in modo asincrono quando i dati in questione diventano disponibili. Il ISourceBlock<>>. Collegarea metodo collega un blocco di flussi di dati di origine a un blocco di destinazione. Un'origine può essere collegata a zero o più destinazioni, mentre queste ultime possono essere collegate da zero o più origini. È possibile aggiungere o rimuovere contemporaneamente blocchi di flussi di dati a o da una pipeline o rete. Tramite i tipi di blocchi di flussi di dati predefiniti vengono gestiti tutti gli aspetti di collegamento e scollegamento thread safety.

Per un esempio di connessione di blocchi di flussi di dati per formare una pipeline di base, vedere procedura dettagliata: creazione di una Pipeline di dati. Per un esempio di connessione di blocchi di flussi di dati per formare una rete più complessa, vedere procedura dettagliata: utilizzo flussi di dati in un'applicazione Windows Form. Per un esempio di scollegamento di una destinazione di un'origine dopo l'offerta di destinazione un messaggio, vedere procedura: scollegare i blocchi di flussi di dati.

Filtro

Quando si chiama il ISourceBlock<>>. Collegarea metodo a cui collegare un'origine a una destinazione, è possibile fornire un delegato che determina se il blocco di destinazione accetta o rifiuta un messaggio in base al valore di tale messaggio. Questo meccanismo di filtro è utile per garantire la ricezione solo di determinati valori da parte di un blocco di flussi di dati. Per la maggior parte dei tipi di blocchi di flussi di dati predefiniti, se un blocco di origine è connesso a più blocchi di destinazione, quando da parte di un blocco di destinazione viene rifiutato un messaggio, quest'ultimo tramite l'origine viene offerto alla destinazione successiva. L'ordine di offerta dei messaggi da parte dell'origine alle destinazioni viene definito dall'origine e può variare a seconda del tipo di origine. L'offerta di un messaggio da parte della maggior parte dei tipi di blocco di origine viene arrestata dopo l'accettazione del messaggio in questione da una destinazione. Fa eccezione a questa regola di BroadcastBlock<> </> > (classe), che offre a tutte le destinazioni, ogni messaggio, anche se alcune destinazioni rifiutare il messaggio. Per un esempio che usa il filtro per elaborare solo determinati messaggi, vedere procedura dettagliata: utilizzo flussi di dati in un'applicazione Windows Form.

System_CAPS_ICON_important.jpg Importante

Poiché ogni tipo di blocco di flussi di dati di origine predefinito garantisce la propagazione all'esterno di questi messaggi nell'ordine in cui vengono ricevuti, ogni messaggio deve essere letto dal blocco di origine prima che da parte di quest'ultimo possa essere elaborato il messaggio successivo. Di conseguenza, quando si utilizzano i filtri per connettere più destinazioni a un'origine, accertarsi che ogni messaggio venga ricevuto da almeno un blocco di destinazione. In caso contrario, si potrebbe verificare un deadlock dell'applicazione.

Passaggio dei messaggi

Il modello di programmazione del flusso di dati è correlato al concetto di passaggio dei messaggi, in cui i componenti indipendenti di un programma di comunicano tra loro mediante l'invio di messaggi. Un modo per propagare i messaggi tra i componenti dell'applicazione consiste nel chiamare il Post<> </> > e DataflowBlock.SendAsync<> </> > metodi per inviare messaggi ai post di blocchi di destinazione del flusso di dati (Post<> </> > funziona in modo sincrono; SendAsync<> </> > funziona in modo asincrono) e ricezione<>>, ReceiveAsync<>>, e TryReceive<> </> > metodi per ricevere messaggi da blocchi di origine. È possibile combinare questi metodi con pipeline o reti del flusso di dati inviando i dati di input al nodo principale (blocco di destinazione) e ricevendo i dati di output dal nodo terminale della pipeline o dai nodi terminali della rete (uno o più blocchi di origine). È inoltre possibile utilizzare il scegliere per leggere dalla prima delle origini fornite sono disponibili dati ed eseguire azioni su tali dati.

Blocchi di origine offrono dati ai blocchi di destinazione chiamando il ITargetBlock<>>. OfferMessage metodo. La risposta a un messaggio offerto viene fornita dal blocco di destinazione in tre modalità: il messaggio può essere accettato, rifiutato o posticipato. Quando la destinazione accetta il messaggio, il OfferMessage restituisce accettato. Quando la destinazione rifiuta il messaggio, il OfferMessage restituisce rifiutato. Quando la destinazione è necessario che non riceva più tutti i messaggi dall'origine, OfferMessage restituisce DecliningPermanently. I tipi di blocchi di origine predefiniti non offrono messaggi alle destinazioni collegate dopo la ricezione di un valore restituito di questo tipo e vengono scollegati automaticamente da queste destinazioni.

Quando il messaggio per un utilizzo successivo viene posticipato un blocco di destinazione di OfferMessage metodo Posposto. Un blocco di destinazione che viene posticipato un messaggio è possibile effettuare chiamate successive il ISourceBlock<>>. ReserveMessage metodo per provare a prenotare il messaggio offerto. A questo punto, il messaggio è ancora disponibile e può essere utilizzato dal blocco di destinazione oppure è stato accettato da un'altra destinazione. Quando il blocco di destinazione in un secondo momento richiede il messaggio o non è più necessario che il messaggio, chiama il ISourceBlock<>>. ConsumeMessage o ReleaseReservation (metodo), rispettivamente. La prenotazione dei messaggi viene in genere utilizzata dai tipi di blocchi di flussi di dati che operano in modalità non greedy. La modalità non greedy verrà illustrata più avanti in questo documento. Anziché riservare un messaggio Posposto, è possibile utilizzare anche un blocco di destinazione di ISourceBlock<>>. ConsumeMessage metodo nel tentativo di utilizzare direttamente il messaggio posposto.

Completamento dei blocchi di flussi di dati

Blocchi di flussi di dati supportano inoltre il concetto di completamento. Non viene eseguito alcun lavoro ulteriore da parte di un blocco di flussi di dati che si trova nello stato completato. Ogni blocco di flussi di dati è associato un System.Threading.Tasks.Task oggetto, noto come un attività di completamento, che rappresenta lo stato di completamento del blocco. Poiché è possibile attendere un attività per completare, tramite le attività di completamento, è possibile attendere uno o più nodi terminali di un flusso di dati di rete alla fine dell'oggetto. Il IDataflowBlock interfaccia definisce il Complete (metodo), che informa il blocco di flussi di dati di una richiesta per il completamento, e completamento proprietà, che restituisce l'attività di completamento di questo tipo di blocco. Entrambi ISourceBlock<> </> > e ITargetBlock<> </> > ereditano il IDataflowBlock interfaccia.

Sono disponibili due modalità per determinare se un blocco di flussi di dati viene completato correttamente, se tramite esso vengono rilevati uno o più errori o se è stato annullato. Il primo modo consiste nel chiamare il Wait metodo sull'attività di completamento in un try - catch blocco (Try - Catch in Visual Basic). Nell'esempio seguente viene creato un ActionBlock<> </> > oggetto che genera ArgumentOutOfRangeException se il valore di input è minore di zero. AggregateException viene generata quando viene chiamato in questo esempio attesa sull'attività di completamento. Il ArgumentOutOfRangeException si accede tramite il InnerExceptions proprietà del AggregateException oggetto.

         // 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 questo esempio viene illustrato il caso in cui un'eccezione non gestita viene inserita nel delegato di un blocco di flussi di dati di esecuzione. Si consiglia di gestire le eccezioni nei corpi di blocchi di questo tipo. In caso contrario, tuttavia, il comportamento del blocco è simile a quello di un annullamento e i messaggi in ingresso non vengono elaborati.

Quando un blocco di flussi di dati viene annullato in modo esplicito, il AggregateException oggetto contiene OperationCanceledException nel InnerExceptions proprietà. Per ulteriori informazioni sull'annullamento del flusso di dati, vedere Abilitazione dell'annullamento più avanti in questo documento.

La seconda modalità per determinare lo stato di completamento di un blocco di flussi di dati è utilizzare una continuazione dell'attività di completamento o le funzionalità asincrone dei linguaggi C# e Visual Basic per attendere in modo asincrono l'attività di completamento. Il delegato fornito per il Task.ContinueWith metodo accetta un attività oggetto che rappresenta l'attività precedente. Nel caso del completamento proprietà, il delegato per la continuazione accetta l'attività di completamento. Nell'esempio seguente è simile a quello precedente, ad eccezione del fatto che viene utilizzato anche il ContinueWith metodo per creare un'attività di completamento che visualizza lo stato dell'operazione del flusso di dati globale.

         // 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.
         */

È anche possibile utilizzare le proprietà, ad esempio IsCanceled nel corpo dell'attività di continuazione per determinare informazioni aggiuntive sullo stato di completamento di un blocco di flussi di dati. Per ulteriori informazioni sulle attività di continuazione e come interagiscono con l'annullamento e la gestione degli errori, vedere concatenamento di attività tramite attività di continuazione, annullamento delle attività, Exception Handling, e NIB: procedura: gestire le eccezioni generate dalle attività.

[go to top]

La libreria del flusso di dati TPL fornisce vari tipi di blocchi di flussi di dati predefiniti. Questi tipi sono suddivisi in tre categorie: blocchi di buffering, blocchi di esecuzione, e blocchi di raggruppamento. Nelle sezioni seguenti vengono descritti i tipi di blocchi che compongono queste categorie.

Blocchi di buffering

Nei blocchi di buffering sono contenuti i dati utilizzati dai consumer di dati. La libreria del flusso di dati TPL fornisce tre tipi di blocchi di buffering: System.Threading.Tasks.Dataflow.BufferBlock<>>, System.Threading.Tasks.Dataflow.BroadcastBlock<>>, e System.Threading.Tasks.Dataflow.WriteOnceBlock<>>.

BufferBlock(T)

Il BufferBlock<> </> > classe rappresenta una struttura di messaggistica asincrona di utilizzo generale. Questa classe archivia una coda di messaggi FIFO (First In, First Out) che possono essere letti da più destinazioni o in cui possono scrivere più origini. Quando una destinazione riceve un messaggio da un BufferBlock<> </> > oggetto messaggio viene rimosso dalla coda dei messaggi. Pertanto, sebbene un BufferBlock<> </> > oggetto può avere più destinazioni, ogni messaggio verrà ricevuto da una sola destinazione. Il BufferBlock<> </> > classe è utile quando si desidera passare più messaggi a un altro componente e tale componente deve ricevere ogni messaggio.

Nell'esempio di base seguente inseriti alcuni Int32 valori da un BufferBlock<> </> > dell'oggetto e quindi legge i valori da tale oggetto.

         // 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
          */

Per un esempio completo che illustra come scrivere e leggere messaggi da un BufferBlock<> </> > di oggetti, vedere procedura: scrivere messaggi in e leggere messaggi da un Dataflow Block.

BroadcastBlock(T)

Il BroadcastBlock<> </> > classe è utile quando è necessario passare più messaggi a un altro componente, ma il componente necessita solo del valore più recente. Questa classe è utile anche quando si vuole trasmettere un messaggio a più componenti.

Esempio di base seguente viene inserito un Double valore per un BroadcastBlock<> </> > oggetto e quindi riletto dall'oggetto più volte. Poiché i valori non vengono rimossi da BroadcastBlock<> </> > oggetti dopo la lettura, lo stesso valore è disponibile ogni volta.

         // 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
          */

Per un esempio completo che illustra come usare BroadcastBlock<> </> > per trasmettere un messaggio a più blocchi di destinazione, vedere procedura: specificare un'utilità di pianificazione in un Dataflow Block.

WriteOnceBlock(T)

Il WriteOnceBlock<> </> > classe è simile al BroadcastBlock<> </> > classe, con la differenza che un WriteOnceBlock<> </> > oggetto può essere scritto una sola volta. È possibile pensare WriteOnceBlock<> </> > come c# readonly (ReadOnly in Visual Basic) (parola chiave), tranne il fatto che un WriteOnceBlock<> </> > oggetto diventa non modificabile dopo la ricezione di un valore anziché in fase di costruzione. Ad esempio il BroadcastBlock<> </> > (classe), quando una destinazione riceve un messaggio da un WriteOnceBlock<> </> > dell'oggetto, il messaggio non viene rimosso dall'oggetto in questione. Pertanto, più destinazioni riceveranno una copia del messaggio. Il WriteOnceBlock<> </> > classe è utile quando si desidera propagare solo il primo di più messaggi.

Nell'esempio di base seguente post più stringa valori da un WriteOnceBlock<> </> > oggetto e quindi vengono riletti dall'oggetto in questione. Poiché un WriteOnceBlock<> </> > oggetto può essere scritto una sola volta solo dopo un WriteOnceBlock<> </> > oggetto riceve un messaggio, i messaggi successivi vengono rimossi.

         // 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
          */

Per un esempio completo che illustra come usare WriteOnceBlock<> </> > per ricevere il valore della prima operazione che viene completata, vedere procedura: scollegare i blocchi di flussi di dati.

Blocchi di esecuzione

Tramite i blocchi di esecuzione viene chiamato un delegato fornito dall'utente per ogni blocco di dati ricevuti. La libreria di flussi di dati TPL fornisce tre tipi di blocchi di esecuzione: ActionBlock<>>, System.Threading.Tasks.Dataflow.TransformBlock<TInput, TOutput>, e System.Threading.Tasks.Dataflow.TransformManyBlock<TInput, TOutput>.</TInput, TOutput> </TInput, TOutput>

ActionBlock(T)

Il ActionBlock<> </> > classe è un blocco di destinazione che chiama un delegato alla ricezione dei dati. Si tratta di un ActionBlock<> </> > oggetto come un delegato che viene eseguito in modo asincrono quando i dati diventano disponibili. Il delegato fornito a un ActionBlock<> </> > oggetto può essere di tipo azione o tipo System.Func<TInput, Task>. Quando si utilizza un ActionBlock<> </> > con azione, l'elaborazione di ogni elemento di input viene considerata completata alla restituzione del delegato. Quando si utilizza un ActionBlock<> </> > con System.Func<TInput, Task>, l'elaborazione di ogni elemento di input viene considerata completata solo quando l'oggetto restituito attività oggetto è stato completato. Tramite questi due meccanismi, è possibile utilizzare ActionBlock<> </> > per l'elaborazione sincrona e asincrona di ogni elemento di input.

Nell'esempio di base seguente post più Int32 valori da un ActionBlock<> </> > oggetto. Il ActionBlock<> </> > oggetto vengono stampati i valori nella console. In questo esempio il blocco viene quindi impostato sullo stato completato e attende il completamento di tutte le attività del flusso di dati.

         // 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
          */

Per esempi completi in cui viene illustrato come utilizzare i delegati con la ActionBlock<> </> > , vedere procedura: eseguire quando un flusso di dati blocco riceve i dati dell'azione.

TransformBlock(TInput, TOutput)

Il TransformBlock<TInput, TOutput> classe è simile al ActionBlock<> </> > classe, ad eccezione del fatto che viene utilizzata sia come origine sia come destinazione.</TInput, TOutput> Il delegato che viene passato a un TransformBlock<TInput, TOutput> oggetto restituisce un valore di tipo TOutput.</TInput, TOutput> Il delegato fornito a un TransformBlock<TInput, TOutput> oggetto può essere di tipo System.Func<TInput, TOutput> o tipo System.Func<TInput, Task>.</TInput, TOutput> Quando si utilizza un TransformBlock<TInput, TOutput> con System.Func<TInput, TOutput>, l'elaborazione di ogni elemento di input viene considerata completata alla restituzione del delegato.</TInput, TOutput> Quando si utilizza un TransformBlock<TInput, TOutput> oggetto utilizzato con System.Func<TInput, Task<TOutput>>, l'elaborazione di ogni elemento di input viene considerata completata solo quando l'oggetto restituito attività oggetto è stato completato.</TInput, TOutput> Come con ActionBlock<>>, tramite questi due meccanismi, è possibile utilizzare TransformBlock<TInput, TOutput> per l'elaborazione sincrona e asincrona di ogni elemento di input.</TInput, TOutput>

Nell'esempio di base seguente viene creato un TransformBlock<TInput, TOutput> oggetto che calcola la radice quadrata dell'input.</TInput, TOutput> Il TransformBlock<TInput, TOutput> richiede Int32 valori come input e produce Double valori come output.</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
          */

Per esempi completi che utilizza TransformBlock<TInput, TOutput> in una rete di blocchi di flussi di dati che esegue l'elaborazione di immagini in un'applicazione Windows Form, vedere procedura dettagliata: utilizzo flussi di dati in un'applicazione Windows Form.</TInput, TOutput>

TransformManyBlock(TInput, TOutput)

Il TransformManyBlock<TInput, TOutput> classe è simile al TransformBlock<TInput, TOutput> classe, con la differenza che TransformManyBlock<TInput, TOutput> produce zero o più valori di output per ogni valore di input, anziché solo un valore di output per ogni valore di input.</TInput, TOutput> </TInput, TOutput> </TInput, TOutput> Il delegato fornito a un TransformManyBlock<TInput, TOutput> oggetto può essere di tipo System.Func<TInput, IEnumerable<TOutput>> o type System.Func<TInput, Task<IEnumerable<TOutput>>>.</TInput, TOutput> Quando si utilizza un TransformManyBlock<TInput, TOutput> con System.Func<TInput, IEnumerable<TOutput>>, l'elaborazione di ogni elemento di input viene considerata completata alla restituzione del delegato.</TInput, TOutput> Quando si utilizza un TransformManyBlock<TInput, TOutput> con System.Func<TInput, Task<IEnumerable<TOutput>>>, l'elaborazione di ogni elemento di input viene considerata completata solo quando l'oggetto restituito System.Threading.Tasks.Task<IEnumerable<TOutput>> oggetto è stato completato.</TInput, TOutput>

Nell'esempio di base seguente viene creato un TransformManyBlock<TInput, TOutput> oggetto che le stringhe vengono suddivise in singole sequenze di caratteri.</TInput, TOutput> Il TransformManyBlock<TInput, TOutput> richiede stringa valori come input e produce Char valori come output.</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
          */

Per esempi completi che utilizzano TransformManyBlock<TInput, TOutput> per generare più output indipendenti per ogni input in una pipeline di dati, vedere procedura dettagliata: creazione di una Pipeline di dati.</TInput, TOutput>

Grado di parallelismo

Ogni ActionBlock<>>, TransformBlock<TInput, TOutput>, e TransformManyBlock<TInput, TOutput> buffer oggetto messaggi di input fino a quando il blocco è pronto per elaborarli.</TInput, TOutput> </TInput, TOutput> Per impostazione predefinita, i messaggi vengono elaborati da queste classi nell'ordine in cui vengono ricevuti, un messaggio alla volta. È inoltre possibile specificare il grado di parallelismo per consentire ActionBlock<>>, TransformBlock<TInput, TOutput> e TransformManyBlock<TInput, TOutput> oggetti da elaborare più messaggi contemporaneamente.</TInput, TOutput> </TInput, TOutput> Per ulteriori informazioni sull'esecuzione simultanea, vedere la sezione Specifica del grado di parallelismo più avanti in questo documento. Per un esempio che imposta il grado di parallelismo per consentire a un blocco di flussi di dati di esecuzione elaborare più messaggi contemporaneamente, vedere procedura: specificare il grado di parallelismo in un Dataflow Block.

Riepilogo dei tipi delegati

Nella tabella seguente sono riepilogati i tipi delegati che è possibile fornire a ActionBlock<>>, TransformBlock<TInput, TOutput>, e TransformManyBlock<TInput, TOutput> oggetti.</TInput, TOutput> </TInput, TOutput> Viene inoltre specificato se il tipo delegato viene eseguito in modo sincrono o asincrono.

TipoTipo delegato sincronoTipo delegato asincrono
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>>>

È inoltre possibile utilizzare le espressioni lambda quando si utilizzano tipi di blocchi di esecuzione. Per un esempio in cui viene illustrato come utilizzare un'espressione lambda con un blocco di esecuzione, vedere procedura: eseguire quando un flusso di dati blocco riceve i dati dell'azione.

Blocchi di raggruppamento

Con i blocchi di raggruppamento è possibile combinare i dati da una o più origini e con vari vincoli. La libreria di flussi di dati TPL fornisce tre tipi di blocchi join: BatchBlock<>>, JoinBlock<T1, T2>, e BatchedJoinBlock<T1, T2>.</T1, T2> </T1, T2>

BatchBlock(T)

Il BatchBlock<> </> > classe combina i set di dati di input, noti come batch, in matrici di dati di output. Specificare la dimensione di ciascun batch quando si crea un BatchBlock<> </> > oggetto. Quando il BatchBlock<> </> > oggetto riceve il numero specificato di elementi di input, viene propagata in modo asincrono all'esterno una matrice contenente gli elementi. Se un BatchBlock<> </> > oggetto è impostato sullo stato completato ma non contiene elementi sufficienti per formare un batch, viene propagata all'esterno una matrice finale contenente gli elementi di input rimanenti.

Il BatchBlock<> </> > classe viene eseguita in modalità greedy o non-greedy modalità. In modalità greedy, ovvero l'impostazione predefinita, un BatchBlock<> </> > oggetto accetta ogni messaggio che viene offerto e propaga all'esterno una matrice dopo aver ricevuto il numero specificato di elementi. In modalità non greedy, un BatchBlock<> </> > oggetto vengono posticipati tutti i messaggi in ingresso finché non sufficiente origini offerti messaggi al blocco per formare un batch. L'esecuzione in modalità greedy è in genere migliore rispetto a quella non greedy dal momento che necessita di un sovraccarico inferiore di elaborazione. Tuttavia, è possibile utilizzare la modalità non greedy quando è necessario coordinare l'utilizzo da più origini in modo atomico. Specificare la modalità non greedy impostando quantificatore Greedy a False nel dataflowBlockOptions parametro il BatchBlock<> </> > costruttore.

Nell'esempio di base seguente inseriti alcuni Int32 valori da un BatchBlock<> </> > oggetto contenente dieci elementi in un batch. Per garantire che tutti i valori vengano propagati fuori il BatchBlock<>>, questo esempio viene chiamato il Complete metodo. Il Complete metodo imposta la BatchBlock<> </> > oggetto allo stato completato e di conseguenza, il BatchBlock<> </> > oggetto propaga tutti gli elementi rimanenti come batch finale.

         // 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.
          */

Per un esempio completo che utilizza BatchBlock<> </> > per migliorare l'efficienza delle operazioni di inserimento del database, vedere procedura dettagliata: uso di BatchBlock e BatchedJoinBlock per migliorare l'efficienza.

JoinBlock(T1, T2, ...)

Il JoinBlock<T1, T2> e JoinBlock<T1, T2, T3> classi di raccolta di elementi di input e propagati all'esterno System. Tuple<T1, T2> o System. Tuple<T1, T2, T3> gli oggetti che contengono tali elementi.</T1, T2, T3> </T1, T2> </T1, T2, T3> </T1, T2> Il JoinBlock<T1, T2> e JoinBlock<T1, T2, T3> classi ereditano da ITargetBlock<>>.</T1, T2, T3> </T1, T2> Forniscono invece proprietà, Target1, Target2, e Target3, che implementano ITargetBlock<>>.

Ad esempio BatchBlock<>>, JoinBlock<T1, T2> e JoinBlock<T1, T2, T3> operare in modalità greedy o non greedy.</T1, T2, T3> </T1, T2> In modalità greedy, ovvero l'impostazione predefinita, un JoinBlock<T1, T2> o JoinBlock<T1, T2, T3> oggetto accetta ogni messaggio che viene offerto e propaga all'esterno una tupla dopo ciascuna delle relative destinazioni viene ricevuto almeno un messaggio.</T1, T2, T3> </T1, T2> In modalità non greedy, un JoinBlock<T1, T2> o JoinBlock<T1, T2, T3> oggetto vengono posticipati tutti i messaggi in ingresso finché non sono stati offerti i dati necessari per creare una tupla a tutte le destinazioni.</T1, T2, T3> </T1, T2> A questo punto, nel blocco viene utilizzato un protocollo di commit a due fasi per recuperare atomicamente tutti gli elementi richiesti dalle origini. Questo rinvio consente a un'altra entità di utilizzare i dati nel frattempo per permettere al sistema complessivo di avanzare.

Nell'esempio di base seguente viene illustrato un caso in cui un JoinBlock<T1, T2, T3> oggetto richiede più dati per calcolare un valore.</T1, T2, T3> Questo esempio viene creato un JoinBlock<T1, T2, T3> oggetto che richiede due Int32 valori e un Char valore per eseguire un'operazione aritmetica.</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
          */

Per un esempio completo che utilizza JoinBlock<T1, T2> degli oggetti in modalità non greedy per condividere in modo cooperativo una risorsa, vedere procedura: usare JoinBlock per leggere dati da più origini.</T1, T2>

BatchedJoinBlock(T1, T2, ...)

Il BatchedJoinBlock<T1, T2> e BatchedJoinBlock<T1, T2, T3> classi raccolti batch di elementi di input e propagati all'esterno System.Tuple(IList(T1), IList(T2)) o System.Tuple(IList(T1), IList(T2), IList(T3)) gli oggetti che contengono tali elementi.</T1, T2, T3> </T1, T2> Si tratta di BatchedJoinBlock<T1, T2> come una combinazione di BatchBlock<> </> > e JoinBlock<T1, T2>.</T1, T2> </T1, T2> Specificare le dimensioni di ciascun batch quando si crea un BatchedJoinBlock<T1, T2> oggetto.</T1, T2> BatchedJoinBlock<T1, T2> fornisce inoltre le proprietà, Target1 e Target2, che implementano ITargetBlock<>>.</T1, T2> Quando il numero specificato di elementi di input viene ricevuto attraverso tutte le destinazioni, il BatchedJoinBlock<T1, T2> oggetto propaga in modo asincrono un System.Tuple(IList(T1), IList(T2)) oggetto che contiene gli elementi.</T1, T2>

Nell'esempio di base seguente viene creato un BatchedJoinBlock<T1, T2> oggetto contenente i risultati, Int32 valori e gli errori di eccezione oggetti.</T1, T2> In questo esempio vengono eseguite più operazioni e vengono scritti i risultati di Target1 , proprietà ed errori per il Target2 proprietà, del BatchedJoinBlock<T1, T2> oggetto.</T1, T2> Poiché il conteggio delle operazioni riuscite e non è noto in anticipo, il IList<> </> > oggetti consentono di ogni destinazione di ricevere zero o più valori.

         // 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.
          */

Per un esempio completo che utilizza BatchedJoinBlock<T1, T2> per acquisire i risultati e tutte le eccezioni che si verificano durante il programma legge da un database, vedere procedura dettagliata: uso di BatchBlock e BatchedJoinBlock per migliorare l'efficienza.</T1, T2>

[go to top]

È possibile abilitare opzioni aggiuntive fornendo un System.Threading.Tasks.Dataflow.DataflowBlockOptions oggetto al costruttore di tipi di blocchi di flussi di dati. Tramite queste opzioni viene controllato il comportamento dell'utilità di pianificazione mediante la quale vengono gestiti l'attività sottostante e il grado di parallelismo. Il DataflowBlockOptions dispone inoltre di tipi che specificano il comportamento specifico di determinati tipi di blocchi di flussi di dati derivati. Nella tabella seguente viene riepilogato il tipo di opzioni associato a ogni tipo di blocco di flussi di dati.

Tipo di blocco di flussi di datiDataflowBlockOptions tipo
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

Le sezioni seguenti forniscono ulteriori informazioni sui tipi di flussi di dati importanti opzioni per il blocco che sono disponibili tramite il System.Threading.Tasks.Dataflow.DataflowBlockOptions, System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions, e System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions classi.

Specifica dell'Utilità di pianificazione

In ogni blocco di flussi di dati predefinito viene utilizzato il meccanismo di pianificazione delle attività TPL per eseguire attività quali la propagazione dei dati in una destinazione, la ricezione dei dati da un'origine e l'esecuzione di delegati definiti dall'utente quando i dati diventano disponibili. Oggetto TaskScheduler è una classe astratta che rappresenta un'utilità di pianificazione che accoda attività nei thread. Utilità di pianificazione predefinita, predefinito, utilizza il ThreadPool classe per accodare ed eseguire il lavoro. È possibile eseguire l'override di utilità di pianificazione predefinita impostando la oggetto TaskScheduler proprietà quando si costruisce un oggetto di blocco di flussi di dati.

Quando tramite la stessa Utilità di pianificazione vengono gestiti più blocchi di flussi di dati, è possibile applicarvi dei criteri. Ad esempio, se più blocchi di flussi di dati sono configurati ognuno per utilizzare l'utilità di pianificazione esclusivo dello stesso ConcurrentExclusiveSchedulerPair dell'oggetto, tutto il lavoro eseguito tramite questi blocchi viene serializzato. Analogamente, se questi blocchi sono configurati per utilizzare l'utilità di pianificazione simultanee dello stesso ConcurrentExclusiveSchedulerPair oggetto e l'utilità di pianificazione è configurata per disporre di un livello massimo di concorrenza, tutto il lavoro di questi blocchi è limitato a quel numero di operazioni simultanee. Per un esempio che utilizza il ConcurrentExclusiveSchedulerPair classe per consentire operazioni di lettura si verificano in parallelo, ma vengono eseguite separatamente da tutte le altre operazioni, vedere le operazioni di scrittura procedura: specificare un'utilità di pianificazione in un Dataflow Block. Per ulteriori informazioni sulle utilità di pianificazione in TPL, vedere il oggetto TaskScheduler argomento relativo alla classe.

Specifica del grado di parallelismo

Per impostazione predefinita, i tipi di blocchi di tre esecuzione forniti dalla libreria del flusso di dati TPL, ActionBlock<>>, TransformBlock<TInput, TOutput>, e TransformManyBlock<TInput, TOutput>, elaborare un messaggio alla volta.</TInput, TOutput> </TInput, TOutput> Tramite questi tipi di blocchi di flussi di dati i messaggi vengono inoltre elaborati nell'ordine in cui vengono ricevuti. Per abilitare questi blocchi di flussi di dati elaborare i messaggi contemporaneamente, impostare il ExecutionDataflowBlockOptions.MaxDegreeOfParallelism proprietà quando si crea l'oggetto di blocco di flussi di dati.

Il valore predefinito di MaxDegreeOfParallelism è 1, che garantisce che il blocco di flussi elabora uno messaggio alla volta. Impostando questa proprietà su un valore maggiore di 1 possono essere elaborati più messaggi contemporaneamente da parte del blocco di flussi di dati. Impostando questa proprietà su DataflowBlockOptions.Unbounded consente l'utilità di pianificazione sottostante gestire il massimo livello di concorrenza.

System_CAPS_ICON_important.jpg Importante

Quando si specifica un grado massimo di parallelismo maggiore di 1, vengono elaborati contemporaneamente più messaggi, pertanto questi ultimi potrebbero non essere elaborati nell'ordine in cui vengono ricevuti. L'ordine in cui i messaggi vengono restituiti dal blocco sarà, tuttavia, correttamente ordinato.

Poiché il MaxDegreeOfParallelism proprietà rappresenta il grado massimo di parallelismo, il blocco di flussi di dati può essere eseguito con un minore grado di parallelismo maggiore di quello specificato. È possibile che nel blocco di flussi di dati venga utilizzato un grado di parallelismo minore per soddisfare i requisiti funzionali o perché vi è una mancanza di risorse di sistema disponibili. Da parte di un blocco di flussi di dati non viene mai scelto un parallelismo maggiore di quello specificato.

Il valore di MaxDegreeOfParallelism è esclusivo per ogni oggetto di blocco di flussi di dati. Ad esempio, se da ognuno dei quattro oggetti del blocco di flussi di dati viene specificato 1 come massimo grado di parallelismo, tutti e quattro gli oggetti del blocco di flussi di dati possono essere potenzialmente eseguiti in parallelo.

Per un esempio che imposta il grado massimo di parallelismo per consentire l'esecuzione in parallelo di operazioni lunghe, vedere procedura: specificare il grado di parallelismo in un Dataflow Block.

Specifica del numero di messaggi per attività

Nei tipi di blocchi di flussi di dati predefiniti vengono utilizzate attività per elaborare più elementi di input. In questo modo è possibile ridurre il numero di oggetti di attività necessari per elaborare i dati, consentendo alle applicazioni un'esecuzione più efficiente. Tuttavia, quando tramite le attività di un set di blocchi di flussi di dati vengono elaborati i dati, è possibile che le attività di altri blocchi di flussi di dati debbano attendere il tempo di elaborazione inserendo in coda i messaggi. Per abilitare la migliore equità tra attività del flusso di dati, impostare il MaxMessagesPerTask proprietà. Quando MaxMessagesPerTask è impostato su DataflowBlockOptions.Unbounded, ossia l'impostazione predefinita, l'attività utilizzata da un blocco di flussi di dati vengono elaborati tutti i messaggi che sono disponibili. Quando MaxMessagesPerTask è impostata su un valore diverso da Unbounded, il blocco di flussi elaborato al massimo questo numero di messaggi per attività oggetto. Sebbene l'impostazione di MaxMessagesPerTask proprietà può aumentare l'equità tra le attività, può causare la generazione di più attività rispetto al necessario, il sistema che può ridurre le prestazioni.

Abilitazione dell'annullamento

TPL fornisce un meccanismo che consente alle attività di coordinare l'annullamento in modo cooperativo. Per abilitare i blocchi di flussi di dati di far parte di questo meccanismo di annullamento, impostare il CancellationToken proprietà. Quando questo CancellationToken oggetto viene impostato sullo stato annullato, tutti i blocchi di flussi di dati che controllano questo token viene terminata l'esecuzione dell'elemento corrente ma non viene avviata l'elaborazione degli elementi successivi. Tramite questi blocchi di flussi di dati vengono inoltre cancellati tutti i messaggi memorizzati nel buffer, vengono rilasciate le connessioni a tutti i blocchi di origine e di destinazione e viene eseguita la transizione allo stato di annullamento. Con la transizione allo stato annullato, il completamento proprietà ha il stato impostata su Canceled, a meno che non si è verificata un'eccezione durante l'elaborazione. In tal caso, stato è impostato su Faulted.

Per un esempio che illustra come utilizzare l'annullamento in un'applicazione Windows Form, vedere procedura: annullare un Dataflow Block. Per ulteriori informazioni sull'annullamento in TPL, vedere annullamento delle attività.

Specifica del comportamento greedy e non greedy a confronto

Diversi tipi di blocchi di raggruppamento del flusso di dati possono essere eseguiti in modalità greedy o non-greedy modalità. Per impostazione predefinita, i tipi di blocchi di flussi di dati predefiniti vengono eseguiti in modalità greedy.

Per il join, ad esempio i tipi di blocchi JoinBlock<T1, T2>, la modalità greedy indica che il blocco accetta immediatamente i dati anche se i dati corrispondenti con cui si desidera creare un join non sono ancora disponibili.</T1, T2> La modalità non greedy indica che nel blocco vengono posticipati tutti i messaggi in ingresso finché non ne è disponibile uno per ciascuna delle relative destinazioni per completare il join. Se uno dei messaggi posposti non è più disponibile, tramite il blocco join vengono rilasciati tutti i messaggi posposti e viene riavviato il processo. Per il BatchBlock<> </> > classe greedy e non-greedy comportamento è simile, con la differenza che in modalità non greedy, un BatchBlock<> </> > oggetto vengono posticipati tutti i messaggi in ingresso finché non è un numero sufficiente disponibili da origini diverse per completare un batch.

Per specificare la modalità non greedy per un blocco di flussi di dati, impostare quantificatore Greedy a False. Per un esempio che illustra come utilizzare la modalità non greedy per consentire a più blocchi join di condividere in modo più efficiente un'origine dati, vedere procedura: utilizzare JoinBlock per leggere dati da più origini.

[go to top]

Anche se la libreria del flusso di dati TPL fornisce molti tipi di blocchi predefiniti, è possibile crearne degli altri tramite cui eseguire comportamenti personalizzati. Implementare il ISourceBlock<> </> > o ITargetBlock<> </> > interfacce direttamente o utilizzare il incapsula<TInput, TOutput> metodo per compilare un blocco complesso che incapsula il comportamento dei tipi di blocchi esistenti.</TInput, TOutput> Per esempi che illustrano come implementare la funzionalità di blocco di flussi di dati personalizzati, vedere procedura dettagliata: creazione di un tipo di blocco di flussi di dati personalizzato.

[go to top]

TitoloDescrizione
Procedura: scrivere e leggere messaggi da un blocco di flussiViene illustrato come scrivere e leggere messaggi da un BufferBlock<> </> > oggetto.
Procedura: implementare un modello di flusso di dati Producer-ConsumerViene descritto come utilizzare il modello di flusso di dati per implementare uno schema producer-consumer, in cui il producer invia messaggi a un blocco di flussi di dati e il consumer legge i messaggi dal blocco in questione.
Procedura: eseguire l'azione alla ricezione di un blocco di flussi di datiViene descritto come fornire delegati ai tipi di blocchi di esecuzione del flusso di dati, ActionBlock<>>, TransformBlock<TInput, TOutput>, e TransformManyBlock<TInput, TOutput>.</TInput, TOutput> </TInput, TOutput>
Procedura dettagliata: Creazione di una Pipeline di datiViene descritto come creare una pipeline di flusso di dati tramite cui viene scaricato un testo dal Web e vengono eseguite operazioni su questo testo.
Procedura: scollegare i blocchi di flussi di datiViene illustrato come utilizzare il collegarea metodo per scollegare un blocco di destinazione dalla relativa origine dopo che l'offerta di un messaggio alla destinazione.
Procedura dettagliata: Utilizzo del flusso di dati in un'applicazione Windows FormViene illustrato come creare una rete di blocchi di flussi di dati tramite cui viene eseguita l'elaborazione di immagini in un'applicazione Windows Form.
Procedura: annullare un blocco di flussi di datiViene illustrato come utilizzare l'annullamento in un'applicazione Windows Form.
Procedura: utilizzare JoinBlock per leggere dati da più originiViene illustrato come utilizzare il JoinBlock<T1, T2> per eseguire un'operazione quando sono disponibili dati da più origini e come utilizzare la modalità non greedy per consentire a più blocchi join di condividere un'origine dati in modo più efficiente.</T1, T2>
Procedura: specificare il grado di parallelismo in un blocco di flussi di datiViene descritto come impostare il MaxDegreeOfParallelism proprietà per abilitare un blocco di flussi di dati di esecuzione elaborare più messaggi contemporaneamente.
Procedura: specificare un'utilità di pianificazione in un blocco di flussi di datiViene illustrato come associare una specifica Utilità di pianificazione quando si utilizza il flusso di dati nell'applicazione.
Procedura dettagliata: Utilizzo di BatchBlock e BatchedJoinBlock per migliorare l'efficienzaViene descritto come utilizzare il BatchBlock<> </> > classe per migliorare l'efficienza del database inserire operazioni e come utilizzare il BatchedJoinBlock<T1, T2> (classe) per acquisire i risultati e tutte le eccezioni che si verificano durante il programma legge da un database.</T1, T2>
Procedura dettagliata: Creazione di un tipo di blocco di flussi di dati personalizzatiVengono illustrati due modi per creare un tipo di blocco di flussi di dati tramite cui viene implementato il comportamento personalizzato.
Task Parallel Library (TPL)Viene introdotta TPL, una libreria tramite cui viene semplificata la programmazione parallela e concorrente nelle applicazioni .NET Framework.
Mostra: