Flusso di dati (Task Parallel Library)Dataflow (Task Parallel Library)

La libreria Task Parallel Library (TPL) fornisce componenti del flusso di dati per aumentare l'affidabilità delle applicazioni abilitate per la concorrenza.The Task Parallel Library (TPL) provides dataflow components to help increase the robustness of concurrency-enabled applications. Questi componenti del flusso di dati vengono definiti collettivamente libreria del flusso di dati TPL.These dataflow components are collectively referred to as the TPL Dataflow Library. 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.This dataflow model promotes actor-based programming by providing in-process message passing for coarse-grained dataflow and pipelining tasks. 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.The dataflow components build on the types and scheduling infrastructure of the TPL and integrate with the C#, Visual Basic, and F# language support for asynchronous programming. 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.These dataflow components are useful when you have multiple operations that must communicate with one another asynchronously or when you want to process data as it becomes available. Si consideri, ad esempio, un'applicazione tramite cui vengono elaborati i dati immagine di una webcam.For example, consider an application that processes image data from a web camera. Tramite il modello del flusso di dati, l'applicazione è in grado di elaborare i fotogrammi delle immagini quando diventano disponibili.By using the dataflow model, the application can process image frames as they become available. Se tramite l'applicazione vengono migliorati i fotogrammi dell'immagine, ad esempio, eseguendo la correzione della luce o la riduzione occhi rossi, è possibile creare una pipeline di componenti del flusso di dati.If the application enhances image frames, for example, by performing light correction or red-eye reduction, you can create a pipeline of dataflow components. 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.Each stage of the pipeline might use more coarse-grained parallelism functionality, such as the functionality that is provided by the TPL, to transform the image.

In questo documento viene fornita una panoramica della libreria del flusso di dati TPL.This document provides an overview of the TPL Dataflow Library. 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.It describes the programming model, the predefined dataflow block types, and how to configure dataflow blocks to meet the specific requirements of your applications.

Nota

La libreria del flusso di dati TPL (spazio dei nomi System.Threading.Tasks.Dataflow) non viene distribuita con .NET.The TPL Dataflow Library (the System.Threading.Tasks.Dataflow namespace) is not distributed with .NET. Per installare lo spazio dei nomi System.Threading.Tasks.Dataflow in Visual Studio, aprire il progetto in Visual Studio, scegliere Gestisci pacchetti NuGet dal menu Progetto ed eseguire una ricerca online del pacchetto System.Threading.Tasks.Dataflow.To install the System.Threading.Tasks.Dataflow namespace in Visual Studio, open your project, choose Manage NuGet Packages from the Project menu, and search online for the System.Threading.Tasks.Dataflow package. In alternativa, per installarlo usando l'interfaccia della riga di comando di .Net Core, eseguire dotnet add package System.Threading.Tasks.Dataflow.Alternatively, to install it using the .Net Core CLI, run dotnet add package System.Threading.Tasks.Dataflow.

Questo documento contiene le seguenti sezioni:This document contains the following sections:

Modello di programmazioneProgramming Model

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.The TPL Dataflow Library provides a foundation for message passing and parallelizing CPU-intensive and I/O-intensive applications that have high throughput and low latency. Offre inoltre un controllo esplicito sul modo in cui i dati vengono memorizzati nel buffer e spostati nel sistema.It also gives you explicit control over how data is buffered and moves around the system. 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.To better understand the dataflow programming model, consider an application that asynchronously loads images from disk and creates a composite of those images. 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.Traditional programming models typically require that you use callbacks and synchronization objects, such as locks, to coordinate tasks and access to shared data. 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.By using the dataflow programming model, you can create dataflow objects that process images as they are read from disk. Nel modello del flusso di dati è possibile dichiarare la modalità di gestione dei dati quando disponibili, nonché tutte le dipendenze tra i dati.Under the dataflow model, you declare how data is handled when it becomes available, and also any dependencies between data. Poiché le dipendenze tra i dati sono gestite dal runtime, è spesso possibile evitare la necessità di sincronizzare l'accesso ai dati condivisi.Because the runtime manages dependencies between data, you can often avoid the requirement to synchronize access to shared data. 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.In addition, because the runtime schedules work based on the asynchronous arrival of data, dataflow can improve responsiveness and throughput by efficiently managing the underlying threads. Per un esempio in cui si usa il modello di programmazione del flusso di dati per implementare l'elaborazione di immagini in un'applicazione Windows Forms, vedere Procedura dettagliata: uso del flusso di dati in un'applicazione Windows Forms.For an example that uses the dataflow programming model to implement image processing in a Windows Forms application, see Walkthrough: Using Dataflow in a Windows Forms Application.

Origini e destinazioniSources and Targets

La libreria del flusso di dati TPL è costituita da blocchi di flussi di dati, vale a dire strutture dei dati in cui i dati vengono memorizzati nel buffer ed elaborati.The TPL Dataflow Library consists of dataflow blocks, which are data structures that buffer and process data. Tramite la libreria TPL vengono definiti tre tipi di blocchi di flussi di dati: blocchi di origine, blocchi di destinazione e blocchi di propagazione.The TPL defines three kinds of dataflow blocks: source blocks, target blocks, and propagator blocks. Un blocco di origine viene utilizzato come origine di dati da cui è possibile leggere.A source block acts as a source of data and can be read from. Un blocco di destinazione viene utilizzato come destinatario di dati in cui è possibile scrivere.A target block acts as a receiver of data and can be written to. 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.A propagator block acts as both a source block and a target block, and can be read from and written to. Tramite la libreria TPL vengono definite le seguenti interfacce: System.Threading.Tasks.Dataflow.ISourceBlock<TOutput> per rappresentare le origini, System.Threading.Tasks.Dataflow.ITargetBlock<TInput> per rappresentare le destinazioni e System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput,TOutput> per rappresentare le propagazioni.The TPL defines the System.Threading.Tasks.Dataflow.ISourceBlock<TOutput> interface to represent sources, System.Threading.Tasks.Dataflow.ITargetBlock<TInput> to represent targets, and System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput,TOutput> to represent propagators. L'interfaccia IPropagatorBlock<TInput,TOutput> eredita sia da ISourceBlock<TOutput> sia da ITargetBlock<TInput>.IPropagatorBlock<TInput,TOutput> inherits from both ISourceBlock<TOutput>, and ITargetBlock<TInput>.

La libreria del flusso di dati TPL fornisce vari tipi di blocchi di flussi di dati predefiniti tramite cui vengono implementate le interfacce ISourceBlock<TOutput>, ITargetBlock<TInput> e IPropagatorBlock<TInput,TOutput>.The TPL Dataflow Library provides several predefined dataflow block types that implement the ISourceBlock<TOutput>, ITargetBlock<TInput>, and IPropagatorBlock<TInput,TOutput> interfaces. Questi tipi di blocchi di flussi di dati sono descritti nella sezione Tipi di blocchi di flussi di dati predefiniti di questo documento.These dataflow block types are described in this document in the section Predefined Dataflow Block Types.

Connessione di blocchiConnecting Blocks

È possibile connettere i blocchi di flussi di dati per creare pipeline, che sono sequenze lineari di blocchi di flussi di dati, o reti, che sono grafici di blocchi di flussi di dati.You can connect dataflow blocks to form pipelines, which are linear sequences of dataflow blocks, or networks, which are graphs of dataflow blocks. Una pipeline è un tipo di rete.A pipeline is one form of network. 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.In a pipeline or network, sources asynchronously propagate data to targets as that data becomes available. Tramite il metodo ISourceBlock<TOutput>.LinkTo un blocco di flussi di dati di origine viene connesso a un blocco di destinazione.The ISourceBlock<TOutput>.LinkTo method links a source dataflow block to a target block. Un'origine può essere collegata a zero o più destinazioni, mentre queste ultime possono essere collegate da zero o più origini.A source can be linked to zero or more targets; targets can be linked from zero or more sources. È possibile aggiungere o rimuovere contemporaneamente blocchi di flussi di dati a o da una pipeline o rete.You can add or remove dataflow blocks to or from a pipeline or network concurrently. Tramite i tipi di blocchi di flussi di dati predefiniti vengono gestiti tutti gli aspetti di collegamento e scollegamento thread safety.The predefined dataflow block types handle all thread-safety aspects of linking and unlinking.

Per un esempio di connessione di blocchi di flussi di dati per formare una pipeline di base, vedere Procedura dettagliata: creazione di una pipeline del flusso di dati.For an example that connects dataflow blocks to form a basic pipeline, see Walkthrough: Creating a Dataflow Pipeline. Per un esempio di connessione di blocchi di flussi di dati per formare una rete più complessa, vedere Procedura dettagliata: uso del flusso di dati in un'applicazione Windows Forms.For an example that connects dataflow blocks to form a more complex network, see Walkthrough: Using Dataflow in a Windows Forms Application. Per un esempio di scollegamento di una destinazione da un'origine dopo l'offerta di un messaggio alla destinazione da parte dell'origine, vedere Procedura: Scollegare i blocchi di flussi di dati.For an example that unlinks a target from a source after the source offers the target a message, see How to: Unlink Dataflow Blocks.

FiltroFiltering

Quando si chiama il metodo ISourceBlock<TOutput>.LinkTo per collegare un'origine a una destinazione, è possibile fornire un delegato tramite cui si stabilisce se da parte del blocco di destinazione viene accettato o rifiutato un messaggio in base al valore del messaggio in questione.When you call the ISourceBlock<TOutput>.LinkTo method to link a source to a target, you can supply a delegate that determines whether the target block accepts or rejects a message based on the value of that message. Questo meccanismo di filtro è utile per garantire la ricezione solo di determinati valori da parte di un blocco di flussi di dati.This filtering mechanism is a useful way to guarantee that a dataflow block receives only certain values. 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.For most of the predefined dataflow block types, if a source block is connected to multiple target blocks, when a target block rejects a message, the source offers that message to the next target. 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.The order in which a source offers messages to targets is defined by the source and can vary according to the type of the source. 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.Most source block types stop offering a message after one target accepts that message. Un'eccezione a questa regola è la classe BroadcastBlock<T> mediante la quale ogni messaggio viene offerto a tutte le destinazioni, anche se viene rifiutato da alcune di queste.One exception to this rule is the BroadcastBlock<T> class, which offers each message to all targets, even if some targets reject the message. Per un esempio in cui vengono usati i filtri per elaborare solo determinati messaggi, vedere Procedura dettagliata: uso del flusso di dati in un'applicazione Windows Forms.For an example that uses filtering to process only certain messages, see Walkthrough: Using Dataflow in a Windows Forms Application.

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.Because each predefined source dataflow block type guarantees that messages are propagated out in the order in which they are received, every message must be read from the source block before the source block can process the next message. 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.Therefore, when you use filtering to connect multiple targets to a source, make sure that at least one target block receives each message. In caso contrario, si potrebbe verificare un deadlock dell'applicazione.Otherwise, your application might deadlock.

Passaggio dei messaggiMessage Passing

Il modello di programmazione del flusso di dati è correlato al concetto di passaggio dei messaggi, in base al quale i componenti indipendenti di un programma comunicano con un altro programma inviando messaggi.The dataflow programming model is related to the concept of message passing, where independent components of a program communicate with one another by sending messages. Un modo per propagare i messaggi tra i componenti dell'applicazione consiste nel chiamare i metodi Post e DataflowBlock.SendAsync per inviare messaggi ai post di blocchi di flussi di dati di destinazione (Post funziona in modo sincrono, SendAsync funziona in modo asincrono) e i metodi Receive, ReceiveAsync e TryReceive per ricevere messaggi dai blocchi di origine.One way to propagate messages among application components is to call the Post and DataflowBlock.SendAsync methods to send messages to target dataflow blocks post (Post acts synchronously; SendAsync acts asynchronously) and the Receive, ReceiveAsync, and TryReceive methods to receive messages from source blocks. È 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).You can combine these methods with dataflow pipelines or networks by sending input data to the head node (a target block), and receiving output data from the terminal node of the pipeline or the terminal nodes of the network (one or more source blocks). È inoltre possibile utilizzare il metodo Choose per leggere dalla prima delle origini fornite con dati disponibili ed eseguire azioni sui dati in questione.You can also use the Choose method to read from the first of the provided sources that has data available and perform action on that data.

I blocchi di origine offrono dati ai blocchi di destinazione chiamando il metodo ITargetBlock<TInput>.OfferMessage.Source blocks offer data to target blocks by calling the ITargetBlock<TInput>.OfferMessage method. La risposta a un messaggio offerto viene fornita dal blocco di destinazione in tre modalità: il messaggio può essere accettato, rifiutato o posticipato.The target block responds to an offered message in one of three ways: it can accept the message, decline the message, or postpone the message. Quando il messaggio viene accettato dalla destinazione, il metodo OfferMessage restituisce Accepted.When the target accepts the message, the OfferMessage method returns Accepted. Quando il messaggio viene rifiutato dalla destinazione, il metodo OfferMessage restituisce Declined.When the target declines the message, the OfferMessage method returns Declined. Quando da parte della destinazione viene richiesto di non ricevere più messaggi dall'origine, il metodo OfferMessage restituisce DecliningPermanently.When the target requires that it no longer receives any messages from the source, OfferMessage returns 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.The predefined source block types do not offer messages to linked targets after such a return value is received, and they automatically unlink from such targets.

Quando tramite un blocco di destinazione il messaggio viene posticipato per un utilizzo successivo, il metodo OfferMessage restituisce Postponed.When a target block postpones the message for later use, the OfferMessage method returns Postponed. Un blocco di destinazione che posticipa un messaggio può chiamare successivamente il metodo ISourceBlock<TOutput>.ReserveMessage per provare a prenotare il messaggio offerto.A target block that postpones a message can later call the ISourceBlock<TOutput>.ReserveMessage method to try to reserve the offered message. A questo punto, il messaggio è ancora disponibile e può essere utilizzato dal blocco di destinazione oppure è stato accettato da un'altra destinazione.At this point, the message is either still available and can be used by the target block, or the message has been taken by another target. Quando il messaggio viene richiesto dal blocco di destinazione in un secondo momento o non è più necessario, viene chiamato rispettivamente il metodo ISourceBlock<TOutput>.ConsumeMessage o ReleaseReservation.When the target block later requires the message or no longer needs the message, it calls the ISourceBlock<TOutput>.ConsumeMessage or ReleaseReservation method, respectively. La prenotazione dei messaggi viene in genere utilizzata dai tipi di blocchi di flussi di dati che operano in modalità non greedy.Message reservation is typically used by the dataflow block types that operate in non-greedy mode. La modalità non greedy verrà illustrata più avanti in questo documento.Non-greedy mode is explained later in this document. Anziché riservare un messaggio posposto, in un blocco di destinazione può inoltre essere utilizzato il metodo ISourceBlock<TOutput>.ConsumeMessage per tentare di utilizzare direttamente il messaggio posposto.Instead of reserving a postponed message, a target block can also use the ISourceBlock<TOutput>.ConsumeMessage method to attempt to directly consume the postponed message.

Completamento dei blocchi di flussi di datiDataflow Block Completion

I blocchi di flussi di dati supportano inoltre il concetto di completamento.Dataflow blocks also support the concept of completion. Non viene eseguito alcun lavoro ulteriore da parte di un blocco di flussi di dati che si trova nello stato completato.A dataflow block that is in the completed state does not perform any further work. A ogni blocco di flussi di dati è associato un oggetto System.Threading.Tasks.Task, noto come attività di completamento, che rappresenta lo stato di completamento del blocco.Each dataflow block has an associated System.Threading.Tasks.Task object, known as a completion task, that represents the completion status of the block. Dal momento che è possibile attendere il completamento di un oggetto Task, tramite le attività di completamento è possibile attendere il completamento di uno o più nodi terminali di una rete del flusso di dati.Because you can wait for a Task object to finish, by using completion tasks, you can wait for one or more terminal nodes of a dataflow network to finish. Tramite l'interfaccia IDataflowBlock vengono definiti il metodo Complete, mediante il quale il blocco di flussi di dati viene informato del completamento di una relativa richiesta, e la proprietà Completion, che restituisce l'attività di completamento del blocco di flussi di dati.The IDataflowBlock interface defines the Complete method, which informs the dataflow block of a request for it to complete, and the Completion property, which returns the completion task for the dataflow block. Sia ISourceBlock<TOutput> sia ITargetBlock<TInput> ereditano l'interfaccia IDataflowBlock.Both ISourceBlock<TOutput> and ITargetBlock<TInput> inherit the IDataflowBlock interface.

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.There are two ways to determine whether a dataflow block completed without error, encountered one or more errors, or was canceled. La prima consiste nel chiamare il metodo Task.Wait sull'attività di completamento in un blocco try-catch (Try-Catch in Visual Basic).The first way is to call the Task.Wait method on the completion task in a try-catch block (Try-Catch in Visual Basic). Nell'esempio seguente viene creato un oggetto ActionBlock<TInput> tramite cui viene generato ArgumentOutOfRangeException se il valore di input è minore di zero.The following example creates an ActionBlock<TInput> object that throws ArgumentOutOfRangeException if its input value is less than zero. AggregateException viene generato quando in questo esempio viene chiamato il metodo Wait sull'attività di completamento.AggregateException is thrown when this example calls Wait on the completion task. È possibile accedere a ArgumentOutOfRangeException tramite la proprietà InnerExceptions dell'oggetto AggregateException.The ArgumentOutOfRangeException is accessed through the InnerExceptions property of the AggregateException object.

// 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.
*/
         ' Create an ActionBlock<int> object that prints its input
         ' and throws ArgumentOutOfRangeException if the input
         ' is less than zero.
         Dim throwIfNegative = New ActionBlock(Of Integer)(Sub(n)
             Console.WriteLine("n = {0}", n)
             If n < 0 Then
                 Throw New ArgumentOutOfRangeException()
             End If
         End Sub)

         ' 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 ae As AggregateException
            ' If an unhandled exception occurs during dataflow processing, all
            ' exceptions are propagated through an AggregateException object.
            ae.Handle(Function(e)
                Console.WriteLine("Encountered {0}: {1}", e.GetType().Name, e.Message)
                Return True
            End Function)
         End Try

'          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.This example demonstrates the case in which an exception goes unhandled in the delegate of an execution dataflow block. Si consiglia di gestire le eccezioni nei corpi di blocchi di questo tipo.We recommend that you handle exceptions in the bodies of such blocks. In caso contrario, tuttavia, il comportamento del blocco è simile a quello di un annullamento e i messaggi in ingresso non vengono elaborati.However, if you are unable to do so, the block behaves as though it was canceled and does not process incoming messages.

Quando un blocco di flussi di dati viene annullato in modo esplicito, nell'oggetto AggregateException è contenuto OperationCanceledException nella proprietà InnerExceptions.When a dataflow block is canceled explicitly, the AggregateException object contains OperationCanceledException in the InnerExceptions property. Per altre informazioni sull'annullamento del flusso di dati, vedere la sezione Abilitazione dell'annullamento.For more information about dataflow cancellation, see Enabling Cancellation section.

La seconda modalità per determinare lo stato di completamento di un blocco di flussi di dati consiste nell'usare 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.The second way to determine the completion status of a dataflow block is to use a continuation of the completion task, or to use the asynchronous language features of C# and Visual Basic to asynchronously wait for the completion task. Il delegato fornito al metodo Task.ContinueWith accetta un oggetto Task che rappresenta l'attività precedente.The delegate that you provide to the Task.ContinueWith method takes a Task object that represents the antecedent task. Nel caso della proprietà Completion, il delegato per la continuazione accetta l'attività di completamento stessa.In the case of the Completion property, the delegate for the continuation takes the completion task itself. L'esempio seguente è simile al precedente, tranne per il fatto che viene usato anche il metodo ContinueWith per creare un'attività di continuazione che stampa lo stato dell'operazione globale del flusso di dati.The following example resembles the previous one, except that it also uses the ContinueWith method to create a continuation task that prints the status of the overall dataflow operation.

// 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.
*/
         ' Create an ActionBlock<int> object that prints its input
         ' and throws ArgumentOutOfRangeException if the input
         ' is less than zero.
         Dim throwIfNegative = New ActionBlock(Of Integer)(Sub(n)
             Console.WriteLine("n = {0}", n)
             If n < 0 Then
                 Throw New ArgumentOutOfRangeException()
             End If
         End Sub)

         ' Create a continuation task that prints the overall 
         ' task status to the console when the block finishes.
         throwIfNegative.Completion.ContinueWith(Sub(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 ae As AggregateException
            ' If an unhandled exception occurs during dataflow processing, all
            ' exceptions are propagated through an AggregateException object.
            ae.Handle(Function(e)
                Console.WriteLine("Encountered {0}: {1}", e.GetType().Name, e.Message)
                Return True
            End Function)
         End Try

'          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.
'         

È inoltre possibile utilizzare proprietà come IsCanceled nel corpo dell'attività di continuazione per determinare informazioni aggiuntive sullo stato di completamento di un blocco di flussi di dati.You can also use properties such as IsCanceled in the body of the continuation task to determine additional information about the completion status of a dataflow block. Per altre informazioni sulle attività di continuazione e il modo in cui interagiscono con l'annullamento e la gestione degli errori, vedere Concatenamento di attività tramite attività di continuazione, Annullamento delle attività e Gestione delle eccezioni.For more information about continuation tasks and how they relate to cancellation and error handling, see Chaining Tasks by Using Continuation Tasks, Task Cancellation, and Exception Handling.

[vai all'inizio][go to top]

Tipi di blocchi di flussi di dati predefinitiPredefined Dataflow Block Types

La libreria del flusso di dati TPL fornisce vari tipi di blocchi di flussi di dati predefiniti.The TPL Dataflow Library provides several predefined dataflow block types. Questi tipi sono suddivisi in tre categorie: blocchi di buffering, blocchi di esecuzione e blocchi di raggruppamento.These types are divided into three categories: buffering blocks, execution blocks, and grouping blocks. Nelle sezioni seguenti vengono descritti i tipi di blocchi che compongono queste categorie.The following sections describe the block types that make up these categories.

Blocchi di bufferingBuffering Blocks

Nei blocchi di buffering sono contenuti i dati utilizzati dai consumer di dati.Buffering blocks hold data for use by data consumers. La libreria del flusso di dati TPL fornisce tre tipi di blocco di buffering: System.Threading.Tasks.Dataflow.BufferBlock<T>, System.Threading.Tasks.Dataflow.BroadcastBlock<T> e System.Threading.Tasks.Dataflow.WriteOnceBlock<T>.The TPL Dataflow Library provides three buffering block types: System.Threading.Tasks.Dataflow.BufferBlock<T>, System.Threading.Tasks.Dataflow.BroadcastBlock<T>, and System.Threading.Tasks.Dataflow.WriteOnceBlock<T>.

BufferBlock(T)BufferBlock(T)

La classe BufferBlock<T> rappresenta una struttura di messaggistica asincrona di utilizzo generale.The BufferBlock<T> class represents a general-purpose asynchronous messaging structure. 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.This class stores a first in, first out (FIFO) queue of messages that can be written to by multiple sources or read from by multiple targets. Quando da parte di una destinazione viene ricevuto un messaggio da un oggetto BufferBlock<T>, il messaggio viene rimosso dalla coda di messaggi.When a target receives a message from a BufferBlock<T> object, that message is removed from the message queue. Pertanto, sebbene a un oggetto BufferBlock<T> possano essere associate più destinazioni, ogni messaggio verrà ricevuto da una sola destinazione.Therefore, although a BufferBlock<T> object can have multiple targets, only one target will receive each message. La classe BufferBlock<T> è utile quando si vogliono passare più messaggi a un altro componente e tale componente deve ricevere ogni messaggio.The BufferBlock<T> class is useful when you want to pass multiple messages to another component, and that component must receive each message.

Nell'esempio di base seguente vengono inseriti alcuni valori Int32 in un oggetto BufferBlock<T> che, successivamente, vengono riletti dall'oggetto in questione.The following basic example posts several Int32 values to a BufferBlock<T> object and then reads those values back from that object.

// 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
 */
         ' Create a BufferBlock<int> object.
         Dim bufferBlock = New BufferBlock(Of Integer)()

         ' Post several messages to the block.
         For i As Integer = 0 To 2
            bufferBlock.Post(i)
         Next i

         ' Receive the messages back from the block.
         For i As Integer = 0 To 2
            Console.WriteLine(bufferBlock.Receive())
         Next i

'          Output:
'            0
'            1
'            2
'          

Per un esempio completo che illustra come scrivere messaggi in un oggetto BufferBlock<T> e come leggerli da quest'ultimo, vedere Procedura: Scrivere messaggi in un blocco di flussi di dati e leggere messaggi da un blocco di flussi di dati.For a complete example that demonstrates how to write messages to and read messages from a BufferBlock<T> object, see How to: Write Messages to and Read Messages from a Dataflow Block.

BroadcastBlock(T)BroadcastBlock(T)

La classe BroadcastBlock<T> è utile quando è necessario passare più messaggi a un altro componente, ma il componente necessita solo del valore più recente.The BroadcastBlock<T> class is useful when you must pass multiple messages to another component, but that component needs only the most recent value. Questa classe è utile anche quando si vuole trasmettere un messaggio a più componenti.This class is also useful when you want to broadcast a message to multiple components.

Nell'esempio di base seguente viene inserito un valore Double in un oggetto BroadcastBlock<T> che, successivamente, viene riletto più volte dall'oggetto in questione.The following basic example posts a Double value to a BroadcastBlock<T> object and then reads that value back from that object several times. Dal momento che, dopo essere stati letti, i valori non vengono rimossi dagli oggetti BroadcastBlock<T>, lo stesso valore è disponibile ogni volta.Because values are not removed from BroadcastBlock<T> objects after they are read, the same value is available every time.

// 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
 */
         ' Create a BroadcastBlock<double> object.
         Dim broadcastBlock = New BroadcastBlock(Of Double)(Nothing)

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

         ' Receive the messages back from the block several times.
         For i As Integer = 0 To 2
            Console.WriteLine(broadcastBlock.Receive())
         Next i

'          Output:
'            3.14159265358979
'            3.14159265358979
'            3.14159265358979
'          

Per un esempio completo che illustra come usare BroadcastBlock<T> per trasmettere un messaggio a più blocchi di destinazione, vedere Procedura: Specificare un'utilità di pianificazione in un blocco di flussi di dati.For a complete example that demonstrates how to use BroadcastBlock<T> to broadcast a message to multiple target blocks, see How to: Specify a Task Scheduler in a Dataflow Block.

WriteOnceBlock(T)WriteOnceBlock(T)

La classe WriteOnceBlock<T> è simile alla classe BroadcastBlock<T>, con la differenza che in un oggetto WriteOnceBlock<T> è possibile scrivere una sola volta.The WriteOnceBlock<T> class resembles the BroadcastBlock<T> class, except that a WriteOnceBlock<T> object can be written to one time only. L'oggetto WriteOnceBlock<T> può essere considerato come la parola chiave C# readonly (ReadOnly in Visual Basic), con la differenza che un oggetto WriteOnceBlock<T> diventa non modificabile dopo la ricezione di un valore invece che in fase di costruzione.You can think of WriteOnceBlock<T> as being similar to the C# readonly (ReadOnly in Visual Basic) keyword, except that a WriteOnceBlock<T> object becomes immutable after it receives a value instead of at construction. Come per la classe BroadcastBlock<T>, quando da una destinazione riceve un messaggio da un oggetto WriteOnceBlock<T>, il messaggio viene rimosso dalla coda di messaggi.Like the BroadcastBlock<T> class, when a target receives a message from a WriteOnceBlock<T> object, that message is not removed from that object. Pertanto, più destinazioni riceveranno una copia del messaggio.Therefore, multiple targets receive a copy of the message. La classe WriteOnceBlock<T> è utile quando si desidera propagare solo il primo di più messaggi.The WriteOnceBlock<T> class is useful when you want to propagate only the first of multiple messages.

Nell'esempio di base seguente vengono inseriti valori String in un oggetto WriteOnceBlock<T> che, successivamente, vengono riletti dall'oggetto in questione.The following basic example posts multiple String values to a WriteOnceBlock<T> object and then reads the value back from that object. Poiché un oggetto WriteOnceBlock<T> può essere scritto una sola volta, dopo la ricezione di un oggetto WriteOnceBlock<T>, i messaggi successivi vengono rimossi.Because a WriteOnceBlock<T> object can be written to one time only, after a WriteOnceBlock<T> object receives a message, it discards subsequent messages.

// 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
 */
         ' Create a WriteOnceBlock<string> object.
         Dim writeOnceBlock = New WriteOnceBlock(Of String)(Nothing)

         ' 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(Function() writeOnceBlock.Post("Message 1"), Function() writeOnceBlock.Post("Message 2"), Function() 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<T> per ricevere il valore della prima operazione completata, vedere Procedura: Scollegare i blocchi di flussi di dati.For a complete example that demonstrates how to use WriteOnceBlock<T> to receive the value of the first operation that finishes, see How to: Unlink Dataflow Blocks.

Blocchi di esecuzioneExecution Blocks

Tramite i blocchi di esecuzione viene chiamato un delegato fornito dall'utente per ogni blocco di dati ricevuti.Execution blocks call a user-provided delegate for each piece of received data. La libreria del flusso di dati TPL fornisce tre tipi di blocco di esecuzione: ActionBlock<TInput>, System.Threading.Tasks.Dataflow.TransformBlock<TInput,TOutput> e System.Threading.Tasks.Dataflow.TransformManyBlock<TInput,TOutput>.The TPL Dataflow Library provides three execution block types: ActionBlock<TInput>, System.Threading.Tasks.Dataflow.TransformBlock<TInput,TOutput>, and System.Threading.Tasks.Dataflow.TransformManyBlock<TInput,TOutput>.

ActionBlock(T)ActionBlock(T)

La classe ActionBlock<TInput> è un blocco di destinazione tramite cui viene chiamato un delegato alla ricezione dei dati.The ActionBlock<TInput> class is a target block that calls a delegate when it receives data. Si consideri un oggetto ActionBlock<TInput> come un delegato eseguito in modo asincrono quando i dati diventano disponibili.Think of a ActionBlock<TInput> object as a delegate that runs asynchronously when data becomes available. Il delegato fornito a un oggetto ActionBlock<TInput> può essere di tipo Action<T> o di tipo System.Func<TInput, Task>.The delegate that you provide to an ActionBlock<TInput> object can be of type Action<T> or type System.Func<TInput, Task>. Quando si utilizza un oggetto ActionBlock<TInput> con Action<T>, l'elaborazione di ogni elemento di input viene considerata completata alla restituzione del delegato.When you use an ActionBlock<TInput> object with Action<T>, processing of each input element is considered completed when the delegate returns. Quando si utilizza un oggetto ActionBlock<TInput> con System.Func<TInput, Task>, l'elaborazione di ogni elemento di input viene considerata completata solo quando l'oggetto restituito Task viene completato.When you use an ActionBlock<TInput> object with System.Func<TInput, Task>, processing of each input element is considered completed only when the returned Task object is completed. Tramite questi due meccanismi è possibile utilizzare ActionBlock<TInput> sia per l'elaborazione sincrona sia per quella asincrona di ogni elemento di input.By using these two mechanisms, you can use ActionBlock<TInput> for both synchronous and asynchronous processing of each input element.

Nell'esempio di base seguente vengono inseriti più valori Int32 in un oggetto ActionBlock<TInput>.The following basic example posts multiple Int32 values to an ActionBlock<TInput> object. Tramite l'oggetto ActionBlock<TInput> i valori in questione vengono stampati sulla console.The ActionBlock<TInput> object prints those values to the console. In questo esempio il blocco viene quindi impostato sullo stato completato e attende il completamento di tutte le attività del flusso di dati.This example then sets the block to the completed state and waits for all dataflow tasks to finish.

// 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
 */
         ' Create an ActionBlock<int> object that prints values
         ' to the console.
         Dim actionBlock = New ActionBlock(Of Integer)(Function(n) WriteLine(n))

         ' Post several messages to the block.
         For i As Integer = 0 To 2
            actionBlock.Post(i * 10)
         Next i

         ' 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 che illustrano come usare i delegati con la classe ActionBlock<TInput>, vedere Procedura: Eseguire un'azione alla ricezione di dati in un blocco di flussi di dati.For complete examples that demonstrate how to use delegates with the ActionBlock<TInput> class, see How to: Perform Action When a Dataflow Block Receives Data.

TransformBlock(TInput, TOutput)TransformBlock(TInput, TOutput)

La classe TransformBlock<TInput,TOutput> è simile alla classe ActionBlock<TInput>, con la differenza che viene utilizzata sia come origine sia come destinazione.The TransformBlock<TInput,TOutput> class resembles the ActionBlock<TInput> class, except that it acts as both a source and as a target. Il delegato passato a un oggetto TransformBlock<TInput,TOutput> restituisce un valore di tipo TOutput.The delegate that you pass to a TransformBlock<TInput,TOutput> object returns a value of type TOutput. Il delegato fornito a un oggetto TransformBlock<TInput,TOutput> può essere di tipo System.Func<TInput, TOutput> o di tipo System.Func<TInput, Task<TOutput>>.The delegate that you provide to a TransformBlock<TInput,TOutput> object can be of type System.Func<TInput, TOutput> or type System.Func<TInput, Task<TOutput>>. Quando si utilizza un oggetto TransformBlock<TInput,TOutput> con System.Func<TInput, TOutput>, l'elaborazione di ogni elemento di input viene considerata completata alla restituzione del delegato.When you use a TransformBlock<TInput,TOutput> object with System.Func<TInput, TOutput>, processing of each input element is considered completed when the delegate returns. Quando si utilizza un oggetto TransformBlock<TInput,TOutput> utilizzato con System.Func<TInput, Task<TOutput>>, l'elaborazione di ogni elemento di input viene considerata completata solo quando l'oggetto restituito Task<TResult> viene completato.When you use a TransformBlock<TInput,TOutput> object used with System.Func<TInput, Task<TOutput>>, processing of each input element is considered completed only when the returned Task<TResult> object is completed. Analogamente all'oggetto ActionBlock<TInput>, tramite questi due meccanismi, è possibile utilizzare TransformBlock<TInput,TOutput> sia per l'elaborazione sincrona sia per quella asincrona di ogni elemento di input.As with ActionBlock<TInput>, by using these two mechanisms, you can use TransformBlock<TInput,TOutput> for both synchronous and asynchronous processing of each input element.

Nell'esempio di base seguente viene creato un oggetto TransformBlock<TInput,TOutput> con cui si calcola la radice quadrata dell'input.The following basic example creates a TransformBlock<TInput,TOutput> object that computes the square root of its input. L'oggetto TransformBlock<TInput,TOutput> accetta valori Int32 come input e tramite esso vengono generati valori Double come output.The TransformBlock<TInput,TOutput> object takes Int32 values as input and produces Double values as output.

// 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
 */
         ' Create a TransformBlock<int, double> object that 
         ' computes the square root of its input.
         Dim transformBlock = New TransformBlock(Of Integer, Double)(Function(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 i As Integer = 0 To 2
            Console.WriteLine(transformBlock.Receive())
         Next i

'          Output:
'            3.16227766016838
'            4.47213595499958
'            5.47722557505166
'          

Per esempi completi in cui si usa l'oggetto TransformBlock<TInput,TOutput> in una rete di blocchi di flussi di dati che esegue l'elaborazione di immagini in un'applicazione Windows Forms, vedere Procedura dettagliata: uso del flusso di dati in un'applicazione Windows Forms.For complete examples that uses TransformBlock<TInput,TOutput> in a network of dataflow blocks that performs image processing in a Windows Forms application, see Walkthrough: Using Dataflow in a Windows Forms Application.

TransformManyBlock(TInput, TOutput)TransformManyBlock(TInput, TOutput)

La classe TransformManyBlock<TInput,TOutput> è simile alla classe TransformBlock<TInput,TOutput>, ad eccezione del fatto che tramite l'oggetto TransformManyBlock<TInput,TOutput> vengono generati zero o più valori di output per ogni valore di input anziché un solo valore di output per ogni valore di input.The TransformManyBlock<TInput,TOutput> class resembles the TransformBlock<TInput,TOutput> class, except that TransformManyBlock<TInput,TOutput> produces zero or more output values for each input value, instead of only one output value for each input value. Il delegato fornito a un oggetto TransformManyBlock<TInput,TOutput> può essere di tipo System.Func<TInput, IEnumerable<TOutput>> o di tipo System.Func<TInput, Task<IEnumerable<TOutput>>>.The delegate that you provide to a TransformManyBlock<TInput,TOutput> object can be of type System.Func<TInput, IEnumerable<TOutput>> or type System.Func<TInput, Task<IEnumerable<TOutput>>>. Quando si utilizza un oggetto TransformManyBlock<TInput,TOutput> con System.Func<TInput, IEnumerable<TOutput>>, l'elaborazione di ogni elemento di input viene considerata completata alla restituzione del delegato.When you use a TransformManyBlock<TInput,TOutput> object with System.Func<TInput, IEnumerable<TOutput>>, processing of each input element is considered completed when the delegate returns. Quando si utilizza un oggetto TransformManyBlock<TInput,TOutput> con System.Func<TInput, Task<IEnumerable<TOutput>>>, l'elaborazione di ogni elemento di input viene considerata completa solo quando l'oggetto restituito System.Threading.Tasks.Task<IEnumerable<TOutput>> viene completato.When you use a TransformManyBlock<TInput,TOutput> object with System.Func<TInput, Task<IEnumerable<TOutput>>>, processing of each input element is considered complete only when the returned System.Threading.Tasks.Task<IEnumerable<TOutput>> object is completed.

Nell'esempio di base seguente viene creato un oggetto TransformManyBlock<TInput,TOutput> tramite cui le stringhe vengono suddivise in singole sequenze di caratteri.The following basic example creates a TransformManyBlock<TInput,TOutput> object that splits strings into their individual character sequences. L'oggetto TransformManyBlock<TInput,TOutput> accetta valori String come input e tramite esso vengono generati valori Char come output.The TransformManyBlock<TInput,TOutput> object takes String values as input and produces Char values as output.

// 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
 */
         ' Create a TransformManyBlock<string, char> object that splits
         ' a string into its individual characters.
         Dim transformManyBlock = New TransformManyBlock(Of String, Char)(Function(s) s.ToCharArray())

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

         ' Receive all output values from the block.
         For i As Integer = 0 To ("Hello" & "World").Length - 1
            Console.WriteLine(transformManyBlock.Receive())
         Next i

'          Output:
'            H
'            e
'            l
'            l
'            o
'            W
'            o
'            r
'            l
'            d
'          

Per esempi completi in cui si usa TransformManyBlock<TInput,TOutput> per generare più output indipendenti per ogni input in una pipeline del flusso di dati, vedere Procedura dettagliata: creazione di una pipeline del flusso di dati.For complete examples that use TransformManyBlock<TInput,TOutput> to produce multiple independent outputs for each input in a dataflow pipeline, see Walkthrough: Creating a Dataflow Pipeline.

Grado di parallelismoDegree of Parallelism

Tramite ogni oggetto ActionBlock<TInput>, TransformBlock<TInput,TOutput> e TransformManyBlock<TInput,TOutput> i messaggi di input vengono inseriti nel buffer finché il blocco non è pronto per elaborarli.Every ActionBlock<TInput>, TransformBlock<TInput,TOutput>, and TransformManyBlock<TInput,TOutput> object buffers input messages until the block is ready to process them. Per impostazione predefinita, i messaggi vengono elaborati da queste classi nell'ordine in cui vengono ricevuti, un messaggio alla volta.By default, these classes process messages in the order in which they are received, one message at a time. È inoltre possibile specificare il grado di parallelismo per consentire l'elaborazione simultanea di più messaggi da parte degli oggetti ActionBlock<TInput>, TransformBlock<TInput,TOutput> e TransformManyBlock<TInput,TOutput>.You can also specify the degree of parallelism to enable ActionBlock<TInput>, TransformBlock<TInput,TOutput> and TransformManyBlock<TInput,TOutput> objects to process multiple messages concurrently. Per ulteriori informazioni sull'esecuzione simultanea, vedere la sezione Specifica del grado di parallelismo più avanti in questo documento.For more information about concurrent execution, see the section Specifying the Degree of Parallelism later in this document. Per un esempio in cui viene impostato il grado di parallelismo per consentire l'elaborazione di più di un messaggio alla volta da parte di un blocco di flussi di dati di esecuzione, vedere Procedura: Specificare il grado di parallelismo in un blocco di flussi di dati.For an example that sets the degree of parallelism to enable an execution dataflow block to process more than one message at a time, see How to: Specify the Degree of Parallelism in a Dataflow Block.

Riepilogo dei tipi delegatiSummary of Delegate Types

Nella tabella seguente vengono riepilogati i tipi delegati che possono essere forniti agli oggetti ActionBlock<TInput>, TransformBlock<TInput,TOutput> e TransformManyBlock<TInput,TOutput>.The following table summarizes the delegate types that you can provide to ActionBlock<TInput>, TransformBlock<TInput,TOutput>, and TransformManyBlock<TInput,TOutput> objects. Viene inoltre specificato se il tipo delegato viene eseguito in modo sincrono o asincrono.This table also specifies whether the delegate type operates synchronously or asynchronously.

TipoType Tipo delegato sincronoSynchronous Delegate Type Tipo delegato asincronoAsynchronous Delegate Type
ActionBlock<TInput> System.Action System.Func<TInput, Task>
TransformBlock<TInput,TOutput> System.Func<TInput, TOutput> System.Func<TInput, Task<TOutput>>
TransformManyBlock<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.You can also use lambda expressions when you work with execution block types. Per un esempio che illustra come usare un'espressione lambda con un blocco di esecuzione, vedere Procedura: Eseguire un'azione alla ricezione di dati in un blocco di flussi di dati.For an example that shows how to use a lambda expression with an execution block, see How to: Perform Action When a Dataflow Block Receives Data.

Blocchi di raggruppamentoGrouping Blocks

Con i blocchi di raggruppamento è possibile combinare i dati da una o più origini e con vari vincoli.Grouping blocks combine data from one or more sources and under various constraints. La libreria del flusso di dati TPL fornisce tre tipi di blocchi join: BatchBlock<T>, JoinBlock<T1,T2> e BatchedJoinBlock<T1,T2>.The TPL Dataflow Library provides three join block types: BatchBlock<T>, JoinBlock<T1,T2>, and BatchedJoinBlock<T1,T2>.

BatchBlock(T)BatchBlock(T)

Tramite la classe BatchBlock<T> vengono combinati set di dati di input, noti come batch, in matrici di dati di output.The BatchBlock<T> class combines sets of input data, which are known as batches, into arrays of output data. È possibile specificare le dimensioni di ciascun batch quando si crea un oggetto BatchBlock<T>.You specify the size of each batch when you create a BatchBlock<T> object. Quando tramite l'oggetto BatchBlock<T> si riceve il numero specificato di elementi di input, viene propagata all'esterno in modo asincrono una matrice contenente gli elementi in questione.When the BatchBlock<T> object receives the specified count of input elements, it asynchronously propagates out an array that contains those elements. Se un oggetto BatchBlock<T> è impostato sullo stato completato ma in esso non sono contenuti elementi sufficienti per formare un batch, viene propagata all'esterno una matrice finale contenente gli elementi di input rimanenti.If a BatchBlock<T> object is set to the completed state but does not contain enough elements to form a batch, it propagates out a final array that contains the remaining input elements.

La classe BatchBlock<T> viene eseguita in modalità greedy o non greedy.The BatchBlock<T> class operates in either greedy or non-greedy mode. In modalità greedy, vale a dire l'impostazione predefinita, un oggetto BatchBlock<T> accetta ogni messaggio che viene offerto e propaga all'esterno una matrice dopo la ricezione del numero specificato di elementi.In greedy mode, which is the default, a BatchBlock<T> object accepts every message that it is offered and propagates out an array after it receives the specified count of elements. In modalità non greedy, tramite un oggetto BatchBlock<T> vengono posticipati tutti i messaggi in ingresso finché da parte di un numero sufficiente di origini non vengono offerti messaggi al blocco per formare un batch.In non-greedy mode, a BatchBlock<T> object postpones all incoming messages until enough sources have offered messages to the block to form a batch. L'esecuzione in modalità greedy è in genere migliore rispetto a quella non greedy dal momento che necessita di un sovraccarico inferiore di elaborazione.Greedy mode typically performs better than non-greedy mode because it requires less processing overhead. Tuttavia, è possibile utilizzare la modalità non greedy quando è necessario coordinare l'utilizzo da più origini in modo atomico.However, you can use non-greedy mode when you must coordinate consumption from multiple sources in an atomic fashion. Specificare la modalità non greedy impostando la proprietà Greedy su False nel parametro dataflowBlockOptions nel costruttore BatchBlock<T>.Specify non-greedy mode by setting Greedy to False in the dataflowBlockOptions parameter in the BatchBlock<T> constructor.

Nell'esempio di base seguente vengono inseriti alcuni valori Int32 in un oggetto BatchBlock<T> contenente dieci elementi in un batch.The following basic example posts several Int32 values to a BatchBlock<T> object that holds ten elements in a batch. Per garantire che tutti i valori vengano propagati all'esterno dell'oggetto BatchBlock<T>, in questo esempio viene chiamato il metodo Complete.To guarantee that all values propagate out of the BatchBlock<T>, this example calls the Complete method. Tramite il metodo Complete viene impostato l'oggetto BatchBlock<T> sullo stato completato e, pertanto, tramite l'oggetto BatchBlock<T> vengono propagati all'esterno tutti gli elementi rimanenti come batch finale.The Complete method sets the BatchBlock<T> object to the completed state, and therefore, the BatchBlock<T> object propagates out any remaining elements as a final batch.

// 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.
 */
         ' Create a BatchBlock<int> object that holds ten
         ' elements per batch.
         Dim batchBlock = New BatchBlock(Of Integer)(10)

         ' Post several values to the block.
         For i As Integer = 0 To 12
            batchBlock.Post(i)
         Next 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 in cui si usa BatchBlock<T> per migliorare l'efficienza delle operazioni di inserimento del database, vedere Procedura dettagliata: Uso di BatchBlock e BatchedJoinBlock per migliorare l'efficienza.For a complete example that uses BatchBlock<T> to improve the efficiency of database insert operations, see Walkthrough: Using BatchBlock and BatchedJoinBlock to Improve Efficiency.

JoinBlock(T1, T2, ...)JoinBlock(T1, T2, ...)

Tramite le classi JoinBlock<T1,T2> e JoinBlock<T1,T2,T3> vengono raccolti elementi di input e propagati all'esterno oggetti System.Tuple<T1,T2> o System.Tuple<T1,T2,T3> contenenti gli elementi in questione.The JoinBlock<T1,T2> and JoinBlock<T1,T2,T3> classes collect input elements and propagate out System.Tuple<T1,T2> or System.Tuple<T1,T2,T3> objects that contain those elements. Le classi JoinBlock<T1,T2> e JoinBlock<T1,T2,T3> non ereditano da ITargetBlock<TInput>.The JoinBlock<T1,T2> and JoinBlock<T1,T2,T3> classes do not inherit from ITargetBlock<TInput>. Forniscono invece proprietà, Target1, Target2 e Target3, tramite cui viene implementato l'oggetto ITargetBlock<TInput>.Instead, they provide properties, Target1, Target2, and Target3, that implement ITargetBlock<TInput>.

Come BatchBlock<T>, JoinBlock<T1,T2> e JoinBlock<T1,T2,T3> operano in modalità greedy o non greedy.Like BatchBlock<T>, JoinBlock<T1,T2> and JoinBlock<T1,T2,T3> operate in either greedy or non-greedy mode. In modalità greedy, vale a dire l'impostazione predefinita, un oggetto JoinBlock<T1,T2> o JoinBlock<T1,T2,T3> accetta ogni messaggio che viene offerto e tramite esso viene propagata all'esterno una tupla dopo che da ciascuna delle relative destinazioni viene ricevuto almeno un messaggio.In greedy mode, which is the default, a JoinBlock<T1,T2> or JoinBlock<T1,T2,T3> object accepts every message that it is offered and propagates out a tuple after each of its targets receives at least one message. In modalità non greedy, tramite un oggetto JoinBlock<T1,T2> o JoinBlock<T1,T2,T3> vengono posticipati tutti i messaggi in ingresso finché a tutte le destinazioni non sono stati offerti i dati richiesti per creare una tupla.In non-greedy mode, a JoinBlock<T1,T2> or JoinBlock<T1,T2,T3> object postpones all incoming messages until all targets have been offered the data that is required to create a tuple. A questo punto, nel blocco viene utilizzato un protocollo di commit a due fasi per recuperare atomicamente tutti gli elementi richiesti dalle origini.At this point, the block engages in a two-phase commit protocol to atomically retrieve all required items from the sources. Questo rinvio consente a un'altra entità di utilizzare i dati nel frattempo per permettere al sistema complessivo di avanzare.This postponement makes it possible for another entity to consume the data in the meantime, to allow the overall system to make forward progress.

Nell'esempio di base seguente viene illustrato un caso in cui per un oggetto JoinBlock<T1,T2,T3> sono richiesti più dati per il calcolo di un valore.The following basic example demonstrates a case in which a JoinBlock<T1,T2,T3> object requires multiple data to compute a value. In questo esempio viene creato un oggetto JoinBlock<T1,T2,T3> per cui sono richiesti due valori Int32 e un valore Char per eseguire un'operazione aritmetica.This example creates a JoinBlock<T1,T2,T3> object that requires two Int32 values and a Char value to perform an arithmetic operation.

// 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
 */
         ' Create a JoinBlock<int, int, char> object that requires
         ' two numbers and an operator.
         Dim joinBlock = New JoinBlock(Of Integer, Integer, 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("+"c)
         joinBlock.Target3.Post("-"c)

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

         For i As Integer = 0 To 1
            Dim data = joinBlock.Receive()
            Select Case data.Item3
               Case "+"c
                  Console.WriteLine("{0} + {1} = {2}", data.Item1, data.Item2, data.Item1 + data.Item2)
               Case "-"c
                  Console.WriteLine("{0} - {1} = {2}", data.Item1, data.Item2, data.Item1 - data.Item2)
               Case Else
                  Console.WriteLine("Unknown operator '{0}'.", data.Item3)
            End Select
         Next i

'          Output:
'            3 + 5 = 8
'            6 - 4 = 2
'          

Per un esempio completo in cui vengono usati oggetti JoinBlock<T1,T2> in modalità non greedy per condividere una risorsa in modo cooperativo, vedere Procedura: Usare JoinBlock per leggere dati da più origini.For a complete example that uses JoinBlock<T1,T2> objects in non-greedy mode to cooperatively share a resource, see How to: Use JoinBlock to Read Data From Multiple Sources.

BatchedJoinBlock(T1, T2, ...)BatchedJoinBlock(T1, T2, ...)

Tramite le classi BatchedJoinBlock<T1,T2> e BatchedJoinBlock<T1,T2,T3> vengono raccolti batch di elementi di input e vengono propagati all'esterno oggetti System.Tuple(IList(T1), IList(T2)) o System.Tuple(IList(T1), IList(T2), IList(T3)) contenenti gli elementi in questione.The BatchedJoinBlock<T1,T2> and BatchedJoinBlock<T1,T2,T3> classes collect batches of input elements and propagate out System.Tuple(IList(T1), IList(T2)) or System.Tuple(IList(T1), IList(T2), IList(T3)) objects that contain those elements. Si consideri BatchedJoinBlock<T1,T2> come una combinazione di BatchBlock<T> e JoinBlock<T1,T2>.Think of BatchedJoinBlock<T1,T2> as a combination of BatchBlock<T> and JoinBlock<T1,T2>. Specificare le dimensioni di ciascun batch quando si crea un oggetto BatchedJoinBlock<T1,T2>.Specify the size of each batch when you create a BatchedJoinBlock<T1,T2> object. BatchedJoinBlock<T1,T2> fornisce inoltre le proprietà, Target1 e Target2, tramite cui viene implementato ITargetBlock<TInput>.BatchedJoinBlock<T1,T2> also provides properties, Target1 and Target2, that implement ITargetBlock<TInput>. Quando il numero specificato di elementi di input viene ricevuto attraverso tutte le destinazioni, tramite l'oggetto BatchedJoinBlock<T1,T2> viene propagato all'esterno in modo asincrono un oggetto System.Tuple(IList(T1), IList(T2)) contenente gli elementi in questione.When the specified count of input elements are received from across all targets, the BatchedJoinBlock<T1,T2> object asynchronously propagates out a System.Tuple(IList(T1), IList(T2)) object that contains those elements.

Nell'esempio di base seguente viene creato un oggetto BatchedJoinBlock<T1,T2> contenente i risultati, i valori Int32 e gli errori che sono oggetti Exception.The following basic example creates a BatchedJoinBlock<T1,T2> object that holds results, Int32 values, and errors that are Exception objects. In questo esempio vengono eseguite più operazioni e vengono scritti i risultati nella proprietà Target1 e gli errori nella proprietà Target2 dell'oggetto BatchedJoinBlock<T1,T2>.This example performs multiple operations and writes results to the Target1 property, and errors to the Target2 property, of the BatchedJoinBlock<T1,T2> object. Poiché il conteggio delle operazioni riuscite e non riuscite non è noto in anticipo, gli oggetti IList<T> consentono a ogni destinazione di ricevere zero o più valori.Because the count of successful and failed operations is unknown in advance, the IList<T> objects enable each target to receive zero or more values.

 // 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.
  */
         ' For demonstration, create a Func<int, int> that 
         ' returns its argument, or throws ArgumentOutOfRangeException
         ' if the argument is less than zero.
         Dim DoWork As Func(Of Integer, Integer) = Function(n)
            If n < 0 Then
               Throw New ArgumentOutOfRangeException()
            End If
            Return n
         End Function

         ' Create a BatchedJoinBlock<int, Exception> object that holds 
         ' seven elements per batch.
         Dim batchedJoinBlock = New BatchedJoinBlock(Of Integer, Exception)(7)

         ' Post several items to the block.
         For Each i As Integer In New Integer() { 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 e As ArgumentOutOfRangeException
               ' If an error occurred, post the Exception to the 
               ' second target of the block.
               batchedJoinBlock.Target2.Post(e)
            End Try
         Next i

         ' Read the results from the block.
         Dim results = batchedJoinBlock.Receive()

         ' Print the results to the console.

         ' Print the results.
         For Each n As Integer In results.Item1
            Console.WriteLine(n)
         Next n
         ' Print failures.
         For Each e As Exception In results.Item2
            Console.WriteLine(e.Message)
         Next e

'          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 in cui si usa BatchedJoinBlock<T1,T2> per acquisire sia i risultati sia tutte le eccezioni che si verificano durante la lettura da database da parte del programma, vedere Procedura dettagliata: Uso di BatchBlock e BatchedJoinBlock per migliorare l'efficienza.For a complete example that uses BatchedJoinBlock<T1,T2> to capture both the results and any exceptions that occur while the program reads from a database, see Walkthrough: Using BatchBlock and BatchedJoinBlock to Improve Efficiency.

[vai all'inizio][go to top]

Configurazione del comportamento dei blocchi di flussi di datiConfiguring Dataflow Block Behavior

È possibile abilitare opzioni aggiuntive fornendo un oggetto System.Threading.Tasks.Dataflow.DataflowBlockOptions al costruttore dei tipi di blocchi di flussi di dati.You can enable additional options by providing a System.Threading.Tasks.Dataflow.DataflowBlockOptions object to the constructor of dataflow block types. Tramite queste opzioni viene controllato il comportamento dell'utilità di pianificazione mediante la quale vengono gestiti l'attività sottostante e il grado di parallelismo.These options control behavior such the scheduler that manages the underlying task and the degree of parallelism. L'oggetto DataflowBlockOptions dispone inoltre di tipi derivati tramite cui viene fornito il comportamento specifico di determinati tipi di blocchi di flussi di dati.The DataflowBlockOptions also has derived types that specify behavior that is specific to certain dataflow block types. Nella tabella seguente viene riepilogato il tipo di opzioni associato a ogni tipo di blocco di flussi di dati.The following table summarizes which options type is associated with each dataflow block type.

Tipo di blocco di flussi di datiDataflow Block Type Tipo DataflowBlockOptionsDataflowBlockOptions type
BufferBlock<T> DataflowBlockOptions
BroadcastBlock<T> DataflowBlockOptions
WriteOnceBlock<T> DataflowBlockOptions
ActionBlock<TInput> ExecutionDataflowBlockOptions
TransformBlock<TInput,TOutput> ExecutionDataflowBlockOptions
TransformManyBlock<TInput,TOutput> ExecutionDataflowBlockOptions
BatchBlock<T> GroupingDataflowBlockOptions
JoinBlock<T1,T2> GroupingDataflowBlockOptions
BatchedJoinBlock<T1,T2> GroupingDataflowBlockOptions

Nelle sezioni seguenti vengono fornite informazioni aggiuntive sui principali tipi di opzioni dei blocchi di flussi di dati disponibili nelle classi System.Threading.Tasks.Dataflow.DataflowBlockOptions, System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions e System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions.The following sections provide additional information about the important kinds of dataflow block options that are available through the System.Threading.Tasks.Dataflow.DataflowBlockOptions, System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions, and System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions classes.

Specifica dell'Utilità di pianificazioneSpecifying the Task Scheduler

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.Every predefined dataflow block uses the TPL task scheduling mechanism to perform activities such as propagating data to a target, receiving data from a source, and running user-defined delegates when data becomes available. TaskScheduler è una classe astratta che rappresenta un'Utilità di pianificazione mediante la quale vengono inserite in coda le attività nei thread.TaskScheduler is an abstract class that represents a task scheduler that queues tasks onto threads. Tramite l'Utilità di pianificazione predefinita, Default, viene utilizzata la classe ThreadPool per l'inserimento in coda e l'esecuzione del lavoro.The default task scheduler, Default, uses the ThreadPool class to queue and execute work. È possibile eseguire l'override dell'Utilità di pianificazione predefinita impostando la proprietà TaskScheduler quando si costruisce un oggetto del blocco di flussi di dati.You can override the default task scheduler by setting the TaskScheduler property when you construct a dataflow block object.

Quando tramite la stessa Utilità di pianificazione vengono gestiti più blocchi di flussi di dati, è possibile applicarvi dei criteri.When the same task scheduler manages multiple dataflow blocks, it can enforce policies across them. Ad esempio, se più blocchi di flussi di dati sono configurati ognuno per utilizzare l'utilità di pianificazione in esclusiva dello stesso oggetto ConcurrentExclusiveSchedulerPair, tutto il lavoro eseguito tramite questi blocchi viene serializzato.For example, if multiple dataflow blocks are each configured to target the exclusive scheduler of the same ConcurrentExclusiveSchedulerPair object, all work that runs across these blocks is serialized. Analogamente, se questi blocchi sono configurati per utilizzare l'utilità di pianificazione in concorrenza dello stesso oggetto ConcurrentExclusiveSchedulerPair e l'utilità in questione è configurata per disporre di un livello massimo di concorrenza, tutto il lavoro di questi blocchi è limitato a quel numero di operazioni simultanee.Similarly, if these blocks are configured to target the concurrent scheduler of the same ConcurrentExclusiveSchedulerPair object, and that scheduler is configured to have a maximum concurrency level, all work from these blocks is limited to that number of concurrent operations. Per un esempio in cui si usa la classe ConcurrentExclusiveSchedulerPair per consentire l'esecuzione in parallelo delle operazioni di lettura, mentre le operazioni di scrittura vengono eseguite separatamente da tutte le altre operazioni, vedere Procedura: Specificare un'utilità di pianificazione in un blocco di flussi di dati.For an example that uses the ConcurrentExclusiveSchedulerPair class to enable read operations to occur in parallel, but write operations to occur exclusively of all other operations, see How to: Specify a Task Scheduler in a Dataflow Block. Per altre informazioni sulle utilità di pianificazione delle attività in TPL, vedere l'argomento della classe TaskScheduler.For more information about task schedulers in the TPL, see the TaskScheduler class topic.

Specifica del grado di parallelismoSpecifying the Degree of Parallelism

Per impostazione predefinita, tramite i tre tipi di blocchi di esecuzione forniti dalla libreria del flusso di dati TPL, ActionBlock<TInput>, TransformBlock<TInput,TOutput> e TransformManyBlock<TInput,TOutput>, viene elaborato un messaggio alla volta.By default, the three execution block types that the TPL Dataflow Library provides, ActionBlock<TInput>, TransformBlock<TInput,TOutput>, and TransformManyBlock<TInput,TOutput>, process one message at a time. Tramite questi tipi di blocchi di flussi di dati i messaggi vengono inoltre elaborati nell'ordine in cui vengono ricevuti.These dataflow block types also process messages in the order in which they are received. Per consentire a questi blocchi di flussi di dati di elaborare i messaggi contemporaneamente, impostare la proprietà ExecutionDataflowBlockOptions.MaxDegreeOfParallelism quando si crea l'oggetto del blocco di flussi di dati.To enable these dataflow blocks to process messages concurrently, set the ExecutionDataflowBlockOptions.MaxDegreeOfParallelism property when you construct the dataflow block object.

Il valore predefinito di MaxDegreeOfParallelism è 1, che garantisce l'elaborazione di un solo messaggio per volta da parte del blocco di flussi di dati.The default value of MaxDegreeOfParallelism is 1, which guarantees that the dataflow block processes one message at a time. Impostando questa proprietà su un valore maggiore di 1 possono essere elaborati più messaggi contemporaneamente da parte del blocco di flussi di dati.Setting this property to a value that is larger than 1 enables the dataflow block to process multiple messages concurrently. Impostando questa proprietà su DataflowBlockOptions.Unbounded è possibile la gestione del livello massimo di concorrenza da parte dell'Utilità di pianificazione sottostante.Setting this property to DataflowBlockOptions.Unbounded enables the underlying task scheduler to manage the maximum degree of concurrency.

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.When you specify a maximum degree of parallelism that is larger than 1, multiple messages are processed simultaneously, and therefore messages might not be processed in the order in which they are received. L'ordine in cui i messaggi vengono restituiti dal blocco è, tuttavia, lo stesso in cui vengono ricevuti.The order in which the messages are output from the block is, however, the same one in which they are received.

Poiché la proprietà MaxDegreeOfParallelism rappresenta il grado massimo di parallelismo, il blocco di flussi di dati può essere eseguito con un grado di parallelismo minore rispetto a quello specificato.Because the MaxDegreeOfParallelism property represents the maximum degree of parallelism, the dataflow block might execute with a lesser degree of parallelism than you specify. È 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.The dataflow block might use a lesser degree of parallelism to meet its functional requirements or because there is a lack of available system resources. Da parte di un blocco di flussi di dati non viene mai scelto un parallelismo maggiore di quello specificato.A dataflow block never chooses more parallelism than you specify.

Il valore della proprietà MaxDegreeOfParallelism è esclusivo per ogni oggetto del blocco di flussi di dati.The value of the MaxDegreeOfParallelism property is exclusive to each dataflow block object. 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.For example, if four dataflow block objects each specify 1 for the maximum degree of parallelism, all four dataflow block objects can potentially run in parallel.

Per un esempio in cui si imposta il grado massimo di parallelismo per consentire l'esecuzione in parallelo di operazioni lunghe, vedere Procedura: Specificare il grado di parallelismo in un blocco di flussi di dati.For an example that sets the maximum degree of parallelism to enable lengthy operations to occur in parallel, see How to: Specify the Degree of Parallelism in a Dataflow Block.

Specifica del numero di messaggi per attivitàSpecifying the Number of Messages per Task

Nei tipi di blocchi di flussi di dati predefiniti vengono utilizzate attività per elaborare più elementi di input.The predefined dataflow block types use tasks to process multiple input elements. In questo modo è possibile ridurre il numero di oggetti di attività necessari per elaborare i dati, consentendo alle applicazioni un'esecuzione più efficiente.This helps minimize the number of task objects that are required to process data, which enables applications to run more efficiently. 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.However, when the tasks from one set of dataflow blocks are processing data, the tasks from other dataflow blocks might need to wait for processing time by queuing messages. Per abilitare la migliore equità tra attività del flusso di dati, impostare la proprietà MaxMessagesPerTask.To enable better fairness among dataflow tasks, set the MaxMessagesPerTask property. Quando la proprietà MaxMessagesPerTask è impostata su DataflowBlockOptions.Unbounded, vale a dire l'impostazione predefinita, tramite l'attività utilizzata da un blocco di flussi di dati vengono elaborati tutti i messaggi che sono disponibili.When MaxMessagesPerTask is set to DataflowBlockOptions.Unbounded, which is the default, the task used by a dataflow block processes as many messages as are available. Quando la proprietà MaxMessagesPerTask è impostata su un valore diverso da Unbounded, tramite il blocco di flusso di dati viene elaborato al massimo questo numero di messaggi per l'oggetto Task.When MaxMessagesPerTask is set to a value other than Unbounded, the dataflow block processes at most this number of messages per Task object. Sebbene l'impostazione della proprietà MaxMessagesPerTask possa aumentare l'equità tra le attività, può causare la generazione di più attività rispetto al necessario, che possono ridurre le prestazioni.Although setting the MaxMessagesPerTask property can increase fairness among tasks, it can cause the system to create more tasks than are necessary, which can decrease performance.

Abilitazione dell'annullamentoEnabling Cancellation

TPL fornisce un meccanismo che consente alle attività di coordinare l'annullamento in modo cooperativo.The TPL provides a mechanism that enables tasks to coordinate cancellation in a cooperative manner. Per consentire ai blocchi di flussi di dati di far parte di questo meccanismo di annullamento, impostare la proprietà CancellationToken.To enable dataflow blocks to participate in this cancellation mechanism, set the CancellationToken property. Quando l'oggetto CancellationToken è impostato sullo stato di annullamento, da parte di 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.When this CancellationToken object is set to the canceled state, all dataflow blocks that monitor this token finish execution of their current item but do not start processing subsequent items. 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.These dataflow blocks also clear any buffered messages, release connections to any source and target blocks, and transition to the canceled state. Con la transizione allo stato di annullamento, alla proprietà Completion è associata la proprietà Status impostata su Canceled, a meno che non venga generata un'eccezione durante l'elaborazione.By transitioning to the canceled state, the Completion property has the Status property set to Canceled, unless an exception occurred during processing. In questo caso, la proprietà Status è impostata su Faulted.In that case, Status is set to Faulted.

Per un esempio che illustra come usare l'annullamento in un'applicazione Windows Forms, vedere Procedura: Annullare un blocco di flussi di dati.For an example that demonstrates how to use cancellation in a Windows Forms application, see How to: Cancel a Dataflow Block. Per altre informazioni sull'annullamento in TPL, vedere Annullamento delle attività.For more information about cancellation in the TPL, see Task Cancellation.

Specifica del comportamento greedy e non greedy a confrontoSpecifying Greedy Versus Non-Greedy Behavior

Diversi tipi di blocchi di flussi di dati di raggruppamento possono essere eseguiti in modalità greedy o non-greedy.Several grouping dataflow block types can operate in either greedy or non-greedy mode. Per impostazione predefinita, i tipi di blocchi di flussi di dati predefiniti vengono eseguiti in modalità greedy.By default, the predefined dataflow block types operate in greedy mode.

Per i tipi di blocchi join come JoinBlock<T1,T2>, la modalità greedy indica che il blocco accetta immediatamente i dati anche se quelli corrispondenti con cui è stato creato un join non sono ancora disponibili.For join block types such as JoinBlock<T1,T2>, greedy mode means that the block immediately accepts data even if the corresponding data with which to join is not yet available. 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.Non-greedy mode means that the block postpones all incoming messages until one is available on each of its targets to complete the join. Se uno dei messaggi posposti non è più disponibile, tramite il blocco join vengono rilasciati tutti i messaggi posposti e viene riavviato il processo.If any of the postponed messages are no longer available, the join block releases all postponed messages and restarts the process. Per la classe BatchBlock<T>, il comportamento greedy e non greedy è simile, ad eccezione del fatto che nella modalità non greedy, tramite un oggetto BatchBlock<T> vengono posticipati tutti i messaggi in ingresso finché non è disponibile un numero sufficiente da origini diverse per completare un batch.For the BatchBlock<T> class, greedy and non-greedy behavior is similar, except that under non-greedy mode, a BatchBlock<T> object postpones all incoming messages until enough are available from distinct sources to complete a batch.

Per specificare la modalità non greedy per un blocco di flussi di dati, impostare la proprietà Greedy su False.To specify non-greedy mode for a dataflow block, set Greedy to False. Per un esempio che illustra come usare la modalità non greedy per consentire la condivisione più efficiente di un'origine dati da parte di più blocchi join, vedere Procedura: Usare JoinBlock per leggere dati da più origini.For an example that demonstrates how to use non-greedy mode to enable multiple join blocks to share a data source more efficiently, see How to: Use JoinBlock to Read Data From Multiple Sources.

[vai all'inizio][go to top]

Blocchi di flussi di dati personalizzatiCustom Dataflow Blocks

Anche se la libreria del flusso di dati TPL fornisce molti tipi di blocchi predefiniti, è possibile crearne degli altri tramite cui eseguire comportamenti personalizzati.Although the TPL Dataflow Library provides many predefined block types, you can create additional block types that perform custom behavior. Implementare le interfacce ISourceBlock<TOutput> o ITargetBlock<TInput> direttamente o utilizzare il metodo Encapsulate per compilare un blocco complesso in cui viene incapsulato il comportamento di tipi di blocchi esistenti.Implement the ISourceBlock<TOutput> or ITargetBlock<TInput> interfaces directly or use the Encapsulate method to build a complex block that encapsulates the behavior of existing block types. Per esempi che illustrano come implementare la funzionalità relativa al blocco di flussi di dati personalizzato, vedere Procedura dettagliata: Creazione di un tipo di blocco di flussi di dati personalizzato.For examples that show how to implement custom dataflow block functionality, see Walkthrough: Creating a Custom Dataflow Block Type.

[vai all'inizio][go to top]

TitoloTitle DescriptionDescription
Procedura: Scrivere messaggi in un blocco di flussi di dati e leggere messaggi da un blocco di flussi di datiHow to: Write Messages to and Read Messages from a Dataflow Block Viene illustrato come scrivere messaggi in un oggetto BufferBlock<T> e come leggerli da quest'ultimo.Demonstrates how to write messages to and read messages from a BufferBlock<T> object.
Procedura: Implementare un modello di flusso di dati producer-consumerHow to: Implement a Producer-Consumer Dataflow Pattern Viene 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.Describes how to use the dataflow model to implement a producer-consumer pattern, where the producer sends messages to a dataflow block, and the consumer reads messages from that block.
Procedura: Eseguire un'azione alla ricezione di dati in un blocco di flussi di datiHow to: Perform Action When a Dataflow Block Receives Data Viene descritto come fornire delegati ai tipi di blocchi di flussi di dati di esecuzione, ActionBlock<TInput>, TransformBlock<TInput,TOutput> e TransformManyBlock<TInput,TOutput>.Describes how to provide delegates to the execution dataflow block types, ActionBlock<TInput>, TransformBlock<TInput,TOutput>, and TransformManyBlock<TInput,TOutput>.
Procedura dettagliata: Creazione di una pipeline del flusso di datiWalkthrough: Creating a Dataflow Pipeline Viene descritto come creare una pipeline di flusso di dati tramite cui viene scaricato un testo dal Web e vengono eseguite operazioni su questo testo.Describes how to create a dataflow pipeline that downloads text from the web and performs operations on that text.
Procedura: Scollegare i blocchi di flussi di datiHow to: Unlink Dataflow Blocks Illustra come usare il metodo LinkTo per scollegare un blocco di destinazione dall'origine dopo che l'origine ha offerto un messaggio alla destinazione.Demonstrates how to use the LinkTo method to unlink a target block from its source after the source offers a message to the target.
Procedura dettagliata: Uso del flusso di dati in un'applicazione Windows FormsWalkthrough: Using Dataflow in a Windows Forms Application Viene illustrato come creare una rete di blocchi di flussi di dati tramite cui viene eseguita l'elaborazione di immagini in un'applicazione Windows Form.Demonstrates how to create a network of dataflow blocks that perform image processing in a Windows Forms application.
Procedura: Annullare un blocco di flussi di datiHow to: Cancel a Dataflow Block Viene illustrato come utilizzare l'annullamento in un'applicazione Windows Form.Demonstrates how to use cancellation in a Windows Forms application.
Procedura: Usare JoinBlock per leggere dati da più originiHow to: Use JoinBlock to Read Data From Multiple Sources Viene illustrato come utilizzare la classe JoinBlock<T1,T2> per eseguire un'operazione quando i dati sono disponibili da più origini e come utilizzare la modalità non greedy per consentire a più blocchi join di condividere in modo più efficiente un'origine dati.Explains how to use the JoinBlock<T1,T2> class to perform an operation when data is available from multiple sources, and how to use non-greedy mode to enable multiple join blocks to share a data source more efficiently.
Procedura: Specificare il grado di parallelismo in un blocco di flussi di datiHow to: Specify the Degree of Parallelism in a Dataflow Block Viene illustrato come impostare la proprietà MaxDegreeOfParallelism per consentire a un blocco di flussi di dati di esecuzione di elaborare più messaggi alla volta.Describes how to set the MaxDegreeOfParallelism property to enable an execution dataflow block to process more than one message at a time.
Procedura: Specificare un'utilità di pianificazione in un blocco di flussi di datiHow to: Specify a Task Scheduler in a Dataflow Block Viene illustrato come associare una specifica Utilità di pianificazione quando si utilizza il flusso di dati nell'applicazione.Demonstrates how to associate a specific task scheduler when you use dataflow in your application.
Procedura dettagliata: Uso di BatchBlock e BatchedJoinBlock per migliorare l'efficienzaWalkthrough: Using BatchBlock and BatchedJoinBlock to Improve Efficiency Viene descritto come utilizzare la classe BatchBlock<T> per migliorare l'efficienza delle operazioni di inserimento nel database e come utilizzare la classe BatchedJoinBlock<T1,T2> per acquisire i risultati e tutte le eccezioni che si verificano durante la lettura da un database da parte del programma.Describes how to use the BatchBlock<T> class to improve the efficiency of database insert operations, and how to use the BatchedJoinBlock<T1,T2> class to capture both the results and any exceptions that occur while the program reads from a database.
Procedura dettagliata: Creazione di un tipo di blocco di flussi di dati personalizzatoWalkthrough: Creating a Custom Dataflow Block Type Vengono illustrati due modi per creare un tipo di blocco di flussi di dati tramite cui viene implementato il comportamento personalizzato.Demonstrates two ways to create a dataflow block type that implements custom behavior.
Task Parallel Library (TPL)Task Parallel Library (TPL) Viene introdotta TPL, una libreria tramite cui viene semplificata la programmazione parallela e concorrente nelle applicazioni .NET Framework.Introduces the TPL, a library that simplifies parallel and concurrent programming in .NET Framework applications.