Procedura: eseguire un'azione alla ricezione di dati in un blocco di flussi di datiHow to: Perform Action When a Dataflow Block Receives Data

Tramite i tipi di blocchi di flussi di esecuzione viene chiamato un delegato fornito dall'utente alla ricezione dei dati.Execution dataflow block types call a user-provided delegate when they receive data. Le classi System.Threading.Tasks.Dataflow.ActionBlock<TInput>, System.Threading.Tasks.Dataflow.TransformBlock<TInput,TOutput> e System.Threading.Tasks.Dataflow.TransformManyBlock<TInput,TOutput> sono tipi di blocchi di flussi di dati di esecuzione.The System.Threading.Tasks.Dataflow.ActionBlock<TInput>, System.Threading.Tasks.Dataflow.TransformBlock<TInput,TOutput>, and System.Threading.Tasks.Dataflow.TransformManyBlock<TInput,TOutput> classes are execution dataflow block types. È possibile utilizzare la parola chiave delegate (Sub in Visual Basic), Action<T>, Func<T,TResult> o un'espressione lambda, quando viene fornita una funzione lavoro a un blocco di flussi di dati di esecuzione.You can use the delegate keyword (Sub in Visual Basic), Action<T>, Func<T,TResult>, or a lambda expression when you provide a work function to an execution dataflow block. In questo documento viene descritto come utilizzare Func<T,TResult> e le espressioni lambda per eseguire l'azione nei blocchi di esecuzione.This document describes how to use Func<T,TResult> and lambda expressions to perform action in execution blocks.

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.

EsempioExample

Nell'esempio seguente viene utilizzato un flusso di dati per leggere un file da un disco e viene calcolato il numero di byte del file in questione che corrisponde a zero.The following example uses dataflow to read a file from disk and computes the number of bytes in that file that are equal to zero. Vengono utilizzati TransformBlock<TInput,TOutput> per leggere il file e calcolare il numero di byte zero e ActionBlock<TInput> per stampare il numero di byte zero sulla console.It uses TransformBlock<TInput,TOutput> to read the file and compute the number of zero bytes, and ActionBlock<TInput> to print the number of zero bytes to the console. Tramite l'oggetto TransformBlock<TInput,TOutput> viene specificato un oggetto Func<T,TResult> per eseguire il lavoro quando vengono ricevuti i dati da parte dei blocchi.The TransformBlock<TInput,TOutput> object specifies a Func<T,TResult> object to perform work when the blocks receive data. Nell'oggetto ActionBlock<TInput> viene utilizzata un'espressione lambda per stampare sulla console il numero di byte zero che vengono letti.The ActionBlock<TInput> object uses a lambda expression to print to the console the number of zero bytes that are read.

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

// Demonstrates how to provide delegates to exectution dataflow blocks.
class DataflowExecutionBlocks
{
   // Computes the number of zero bytes that the provided file
   // contains.
   static int CountBytes(string path)
   {
      byte[] buffer = new byte[1024];
      int totalZeroBytesRead = 0;
      using (var fileStream = File.OpenRead(path))
      {
         int bytesRead = 0;
         do
         {
            bytesRead = fileStream.Read(buffer, 0, buffer.Length);
            totalZeroBytesRead += buffer.Count(b => b == 0);
         } while (bytesRead > 0);
      }

      return totalZeroBytesRead;
   }

   static void Main(string[] args)
   {
      // Create a temporary file on disk.
      string tempFile = Path.GetTempFileName();

      // Write random data to the temporary file.
      using (var fileStream = File.OpenWrite(tempFile))
      {
         Random rand = new Random();
         byte[] buffer = new byte[1024];
         for (int i = 0; i < 512; i++)
         {
            rand.NextBytes(buffer);
            fileStream.Write(buffer, 0, buffer.Length);
         }
      }

      // Create an ActionBlock<int> object that prints to the console 
      // the number of bytes read.
      var printResult = new ActionBlock<int>(zeroBytesRead =>
      {
         Console.WriteLine("{0} contains {1} zero bytes.",
            Path.GetFileName(tempFile), zeroBytesRead);
      });

      // Create a TransformBlock<string, int> object that calls the 
      // CountBytes function and returns its result.
      var countBytes = new TransformBlock<string, int>(
         new Func<string, int>(CountBytes));

      // Link the TransformBlock<string, int> object to the 
      // ActionBlock<int> object.
      countBytes.LinkTo(printResult);

      // Create a continuation task that completes the ActionBlock<int>
      // object when the TransformBlock<string, int> finishes.
      countBytes.Completion.ContinueWith(delegate { printResult.Complete(); });

      // Post the path to the temporary file to the 
      // TransformBlock<string, int> object.
      countBytes.Post(tempFile);

      // Requests completion of the TransformBlock<string, int> object.
      countBytes.Complete();

      // Wait for the ActionBlock<int> object to print the message.
      printResult.Completion.Wait();

      // Delete the temporary file.
      File.Delete(tempFile);
   }
}

/* Sample output:
tmp4FBE.tmp contains 2081 zero bytes.
*/
Imports System
Imports System.IO
Imports System.Linq
Imports System.Threading.Tasks
Imports System.Threading.Tasks.Dataflow

' Demonstrates how to provide delegates to exectution dataflow blocks.
Friend Class DataflowExecutionBlocks
   ' Computes the number of zero bytes that the provided file
   ' contains.
   Private Shared Function CountBytes(ByVal path As String) As Integer
      Dim buffer(1023) As Byte
      Dim totalZeroBytesRead As Integer = 0
      Using fileStream = File.OpenRead(path)
         Dim bytesRead As Integer = 0
         Do
            bytesRead = fileStream.Read(buffer, 0, buffer.Length)
            totalZeroBytesRead += buffer.Count(Function(b) b = 0)
         Loop While bytesRead > 0
      End Using

      Return totalZeroBytesRead
   End Function

   Shared Sub Main(ByVal args() As String)
      ' Create a temporary file on disk.
      Dim tempFile As String = Path.GetTempFileName()

      ' Write random data to the temporary file.
      Using fileStream = File.OpenWrite(tempFile)
         Dim rand As New Random()
         Dim buffer(1023) As Byte
         For i As Integer = 0 To 511
            rand.NextBytes(buffer)
            fileStream.Write(buffer, 0, buffer.Length)
         Next i
      End Using

      ' Create an ActionBlock<int> object that prints to the console 
      ' the number of bytes read.
      Dim printResult = New ActionBlock(Of Integer)(Sub(zeroBytesRead) Console.WriteLine("{0} contains {1} zero bytes.", Path.GetFileName(tempFile), zeroBytesRead))

      ' Create a TransformBlock<string, int> object that calls the 
      ' CountBytes function and returns its result.
      Dim countBytes = New TransformBlock(Of String, Integer)(New Func(Of String, Integer)(AddressOf DataflowExecutionBlocks.CountBytes))

      ' Link the TransformBlock<string, int> object to the 
      ' ActionBlock<int> object.
      countBytes.LinkTo(printResult)

      ' Create a continuation task that completes the ActionBlock<int>
      ' object when the TransformBlock<string, int> finishes.
      countBytes.Completion.ContinueWith(Sub() printResult.Complete())

      ' Post the path to the temporary file to the 
      ' TransformBlock<string, int> object.
      countBytes.Post(tempFile)

      ' Requests completion of the TransformBlock<string, int> object.
      countBytes.Complete()

      ' Wait for the ActionBlock<int> object to print the message.
      printResult.Completion.Wait()

      ' Delete the temporary file.
      File.Delete(tempFile)
   End Sub
End Class

' Sample output:
'tmp4FBE.tmp contains 2081 zero bytes.
'

Sebbene sia possibile fornire un'espressione lambda a un oggetto TransformBlock<TInput,TOutput>, in questo esempio viene utilizzato l'oggetto Func<T,TResult> per consentire l'utilizzo del metodo CountBytes ad altro codice.Although you can provide a lambda expression to a TransformBlock<TInput,TOutput> object, this example uses Func<T,TResult> to enable other code to use the CountBytes method. Nell'oggetto ActionBlock<TInput> viene utilizzata un'espressione lambda in quanto il lavoro da eseguire è specifico per questa attività e probabilmente non è utile per altro codice.The ActionBlock<TInput> object uses a lambda expression because the work to be performed is specific to this task and is not likely to be useful from other code. Per altre informazioni sull'uso di espressioni lambda nella libreria TPL, vedere Espressioni lambda in PLINQ e TPL.For more information about how lambda expressions work in the Task Parallel Library, see Lambda Expressions in PLINQ and TPL.

La sezione Riepilogo dei tipi delegati del documento Flusso di dati riepiloga i tipi di delegati che è possibile fornire agli oggetti ActionBlock<TInput>, TransformBlock<TInput,TOutput> e TransformManyBlock<TInput,TOutput>.The section Summary of Delegate Types in the Dataflow document summarizes the delegate types that you can provide to ActionBlock<TInput>, TransformBlock<TInput,TOutput>, and TransformManyBlock<TInput,TOutput> objects. Nella tabella viene inoltre specificato se il tipo delegato viene eseguito in modo sincrono o asincrono.The table also specifies whether the delegate type operates synchronously or asynchronously.

Compilazione del codiceCompiling the Code

Copiare il codice di esempio e incollarlo in un progetto di Visual Studio oppure incollarlo in un file denominato DataflowExecutionBlocks.cs (DataflowExecutionBlocks.vb per Visual Basic) e quindi eseguire il comando riportato di seguito in una finestra del prompt dei comandi di Visual Studio.Copy the example code and paste it in a Visual Studio project, or paste it in a file that is named DataflowExecutionBlocks.cs (DataflowExecutionBlocks.vb for Visual Basic), and then run the following command in a Visual Studio Command Prompt window.

Visual C#Visual C#

csc.exe /r:System.Threading.Tasks.Dataflow.dll DataflowExecutionBlocks.cscsc.exe /r:System.Threading.Tasks.Dataflow.dll DataflowExecutionBlocks.cs

Visual BasicVisual Basic

vbc.exe /r:System.Threading.Tasks.Dataflow.dll DataflowExecutionBlocks.vbvbc.exe /r:System.Threading.Tasks.Dataflow.dll DataflowExecutionBlocks.vb

Programmazione efficienteRobust Programming

In questo esempio viene fornito un delegato di tipo Func<T,TResult> all'oggetto TransformBlock<TInput,TOutput> per eseguire l'attività del blocco di flussi di dati in modo sincrono.This example provides a delegate of type Func<T,TResult> to the TransformBlock<TInput,TOutput> object to perform the task of the dataflow block synchronously. Per abilitare un comportamento asincrono del blocco di flussi di dati, fornire un delegato di tipo Func<TResult> a questo tipo di blocco.To enable the dataflow block to behave asynchronously, provide a delegate of type Func<TResult> to the dataflow block. Quando il comportamento di un blocco di flussi di dati è asincrono, l'attività del blocco di flussi di dati viene completata solo quando termina l'oggetto Task<TResult> restituito.When a dataflow block behaves asynchronously, the task of the dataflow block is complete only when the returned Task<TResult> object finishes. Nell'esempio seguente viene modificato il metodo CountBytes e vengono usati gli operatori async e await (Async e Await in Visual Basic) per calcolare in modo asincrono il numero totale di byte che è pari a zero nel file specificato.The following example modifies the CountBytes method and uses the async and await operators (Async and Await in Visual Basic) to asynchronously compute the total number of bytes that are zero in the provided file. Tramite il metodo ReadAsync vengono eseguite operazioni di lettura da file in modo asincrono.The ReadAsync method performs file read operations asynchronously.

// Asynchronously computes the number of zero bytes that the provided file 
// contains.
static async Task<int> CountBytesAsync(string path)
{
   byte[] buffer = new byte[1024];
   int totalZeroBytesRead = 0;
   using (var fileStream = new FileStream(
      path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, true))
   {
      int bytesRead = 0;
      do
      {
         // Asynchronously read from the file stream.
         bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length);
         totalZeroBytesRead += buffer.Count(b => b == 0);
      } while (bytesRead > 0);
   }

   return totalZeroBytesRead;
}
' Asynchronously computes the number of zero bytes that the provided file 
' contains.
Private Shared async Function CountBytesAsync(ByVal path As String) As Task(Of Integer)
   Dim buffer(1023) As Byte
   Dim totalZeroBytesRead As Integer = 0
   Using fileStream = New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, &H1000, True)
      Dim bytesRead As Integer = 0
      Do
         ' Asynchronously read from the file stream.
         bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)
         totalZeroBytesRead += buffer.Count(Function(b) b = 0)
      Loop While bytesRead > 0
   End Using

   Return totalZeroBytesRead
End Function

È inoltre possibile utilizzare le espressioni lambda asincrone per eseguire azioni in un blocco di flussi di dati di esecuzione.You can also use asynchronous lambda expressions to perform action in an execution dataflow block. Nell'esempio seguente viene modificato l'oggetto TransformBlock<TInput,TOutput> utilizzato nell'esempio precedente in modo da utilizzare un'espressione lambda per eseguire il lavoro in modo asincrono.The following example modifies the TransformBlock<TInput,TOutput> object that is used in the previous example so that it uses a lambda expression to perform the work asynchronously.

// Create a TransformBlock<string, int> object that calls the 
// CountBytes function and returns its result.
var countBytesAsync = new TransformBlock<string, int>(async path =>
{
   byte[] buffer = new byte[1024];
   int totalZeroBytesRead = 0;
   using (var fileStream = new FileStream(
      path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000, true))
   {
      int bytesRead = 0;
      do
      {
         // Asynchronously read from the file stream.
         bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length);
         totalZeroBytesRead += buffer.Count(b => b == 0);
      } while (bytesRead > 0);
   }

   return totalZeroBytesRead;
});
' Create a TransformBlock<string, int> object that calls the 
' CountBytes function and returns its result.
Dim countBytesAsync = New TransformBlock(Of String, Integer)(async Function(path)
         ' Asynchronously read from the file stream.
    Dim buffer(1023) As Byte
    Dim totalZeroBytesRead As Integer = 0
    Using fileStream = New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, &H1000, True)
        Dim bytesRead As Integer = 0
        Do
            bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length)
            totalZeroBytesRead += buffer.Count(Function(b) b = 0)
        Loop While bytesRead > 0
    End Using
    Return totalZeroBytesRead
End Function)

Vedere ancheSee Also

Flusso di datiDataflow