C#idiomatic C#
how-to-perform-action-when-a-dataflow-block-receives-datastandard/parallel-programming

Async and concurrency

How to: Perform Action When a Dataflow Block Receives Data

Learn more about: How to: Perform Action When a Dataflow Block Receives Data

  • page standard/parallel-programming/how-to-perform-action-when-a-dataflow-block-receives-data
  • updated 03/30/2017

Execution dataflow block types call a user-provided delegate when they receive data. The System.Threading.Tasks.Dataflow.ActionBlock, System.Threading.Tasks.Dataflow.TransformBlock, and System.Threading.Tasks.Dataflow.TransformManyBlock classes are execution dataflow block types. You can use the delegate keyword (Sub in Visual Basic), System.Action, System.Func, or a lambda expression when you provide a work function to an execution dataflow block. This document describes how to use System.Func and lambda expressions to perform action in execution blocks.

Example

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. It uses System.Threading.Tasks.Dataflow.TransformBlock to read the file and compute the number of zero bytes, and System.Threading.Tasks.Dataflow.ActionBlock to print the number of zero bytes to the console. The System.Threading.Tasks.Dataflow.TransformBlock object specifies a System.Func object to perform work when the blocks receive data. The System.Threading.Tasks.Dataflow.ActionBlock object uses a lambda expression to print to the console the number of zero bytes that are read.

sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_executionblocks/cs/dataflowexecutionblocks.cs1

csharp
// <snippet1>
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($"{Path.GetFileName(tempFile)} contains {zeroBytesRead} zero bytes.");
      });

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

class Program2
{
   // <snippet2>
   // 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;
   }
   // </snippet2>

   static void Foo()
   {
      // <snippet3>
      // 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;
      });
      // </snippet3>
   }
}

sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_executionblocks/vb/dataflowexecutionblocks.vb1

vb
' <snippet1>
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.
'
' </snippet1>


Friend Class Program2
    ' <snippet2>
    ' 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
    ' </snippet2>

    Private Shared Sub Foo()
        ' <snippet3>
        ' 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)
        ' </snippet3>
    End Sub
End Class

Although you can provide a lambda expression to a System.Threading.Tasks.Dataflow.TransformBlock object, this example uses System.Func to enable other code to use the CountBytes method. The System.Threading.Tasks.Dataflow.ActionBlock 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. For more information about how lambda expressions work in the Task Parallel Library, see Lambda Expressions in PLINQ and TPL.

The section Summary of Delegate Types in the Dataflow document summarizes the delegate types that you can provide to System.Threading.Tasks.Dataflow.ActionBlock, System.Threading.Tasks.Dataflow.TransformBlock, and System.Threading.Tasks.Dataflow.TransformManyBlock objects. The table also specifies whether the delegate type operates synchronously or asynchronously.

Robust Programming

This example provides a delegate of type System.Func to the System.Threading.Tasks.Dataflow.TransformBlock object to perform the task of the dataflow block synchronously. To enable the dataflow block to behave asynchronously, provide a delegate of type Func<T, Task<TResult>> to the dataflow block. When a dataflow block behaves asynchronously, the task of the dataflow block is complete only when the returned System.Threading.Tasks.Task object finishes. 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. The System.IO.FileStream.ReadAsync method performs file read operations asynchronously.

sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_executionblocks/cs/dataflowexecutionblocks.cs2

csharp
// <snippet1>
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($"{Path.GetFileName(tempFile)} contains {zeroBytesRead} zero bytes.");
      });

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

class Program2
{
   // <snippet2>
   // 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;
   }
   // </snippet2>

   static void Foo()
   {
      // <snippet3>
      // 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;
      });
      // </snippet3>
   }
}

sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_executionblocks/vb/dataflowexecutionblocks.vb2

vb
' <snippet1>
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.
'
' </snippet1>


Friend Class Program2
    ' <snippet2>
    ' 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
    ' </snippet2>

    Private Shared Sub Foo()
        ' <snippet3>
        ' 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)
        ' </snippet3>
    End Sub
End Class

You can also use asynchronous lambda expressions to perform action in an execution dataflow block. The following example modifies the System.Threading.Tasks.Dataflow.TransformBlock object that is used in the previous example so that it uses a lambda expression to perform the work asynchronously.

sample 路 csharpsamples/snippets/csharp/VS_Snippets_Misc/tpldataflow_executionblocks/cs/dataflowexecutionblocks.cs3

csharp
// <snippet1>
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($"{Path.GetFileName(tempFile)} contains {zeroBytesRead} zero bytes.");
      });

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

class Program2
{
   // <snippet2>
   // 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;
   }
   // </snippet2>

   static void Foo()
   {
      // <snippet3>
      // 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;
      });
      // </snippet3>
   }
}

sample 路 vbsamples/snippets/visualbasic/VS_Snippets_Misc/tpldataflow_executionblocks/vb/dataflowexecutionblocks.vb3

vb
' <snippet1>
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.
'
' </snippet1>


Friend Class Program2
    ' <snippet2>
    ' 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
    ' </snippet2>

    Private Shared Sub Foo()
        ' <snippet3>
        ' 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)
        ' </snippet3>
    End Sub
End Class

See also