Procedura: Specificare un'utilità di pianificazione in un blocco di flussi di datiHow to: Specify a Task Scheduler in a Dataflow Block

In questo documento viene illustrato come associare una specifica utilità di pianificazione delle attività quando si utilizza il flusso di dati nell'applicazione.This document demonstrates how to associate a specific task scheduler when you use dataflow in your application. Nell'esempio viene usata la classe System.Threading.Tasks.ConcurrentExclusiveSchedulerPair in un'applicazione Windows Forms per visualizzare quando le attività del lettore sono attive e quando invece lo è una del writer.The example uses the System.Threading.Tasks.ConcurrentExclusiveSchedulerPair class in a Windows Forms application to show when reader tasks are active and when a writer task is active. Viene inoltre utilizzato il metodo TaskScheduler.FromCurrentSynchronizationContext per consentire a un blocco di flussi di dati l'esecuzione nel thread dell'interfaccia utente.It also uses the TaskScheduler.FromCurrentSynchronizationContext method to enable a dataflow block to run on the user-interface thread.

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.

Per creare l'applicazione Windows FormsTo Create the Windows Forms Application

  1. Creare un progetto Windows Forms Application Visual C# o Visual Basic.Create a Visual C# or Visual Basic Windows Forms Application project. Nei passaggi seguenti il progetto viene denominato WriterReadersWinForms.In the following steps, the project is named WriterReadersWinForms.

  2. Nella finestra di progettazione del form per il form principale, Form1.cs (Form1.vb per Visual Basic), aggiungere quattro controlli CheckBox.On the form designer for the main form, Form1.cs (Form1.vb for Visual Basic), add four CheckBox controls. Impostare la proprietà Text su Reader 1 per checkBox1, Reader 2 per checkBox2, Reader 3 per checkBox3 e Writer per checkBox4.Set the Text property to Reader 1 for checkBox1, Reader 2 for checkBox2, Reader 3 for checkBox3, and Writer for checkBox4. Impostare la proprietà Enabled per ogni controllo su False.Set the Enabled property for each control to False.

  3. Aggiungere un controllo Timer al form.Add a Timer control to the form. Impostare la proprietà Interval su 2500.Set the Interval property to 2500.

Aggiunta di funzionalità del flusso di datiAdding Dataflow Functionality

In questa sezione viene descritto come creare i blocchi di flussi di dati che fanno parte dell'applicazione e come associare ognuno di essi a un'utilità di pianificazione delle attività.This section describes how to create the dataflow blocks that participate in the application and how to associate each one with a task scheduler.

Per aggiungere funzionalità del flusso di dati all'applicazioneTo Add Dataflow Functionality to the Application

  1. Nel progetto aggiungere un riferimento a System.Threading.Tasks.Dataflow.dll.In your project, add a reference to System.Threading.Tasks.Dataflow.dll.

  2. Assicurarsi che in Form1.cs (Form1.vb per Visual Basic) siano contenute le seguenti istruzioni using (Imports in Visual Basic).Ensure that Form1.cs (Form1.vb for Visual Basic) contains the following using statements (Imports in Visual Basic).

    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Threading.Tasks.Dataflow;
    using System.Windows.Forms;
    
    Imports System.Threading
    Imports System.Threading.Tasks
    Imports System.Threading.Tasks.Dataflow
    
  3. Aggiungere un membro dati BroadcastBlock<T> alla classe Form1.Add a BroadcastBlock<T> data member to the Form1 class.

    // Broadcasts values to an ActionBlock<int> object that is associated
    // with each check box.
    BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);
    
    ' Broadcasts values to an ActionBlock<int> object that is associated
    ' with each check box.
    Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)
    
  4. Nel costruttore Form1, dopo la chiamata a InitializeComponent, creare un oggetto ActionBlock<TInput> tramite cui viene alternato lo stato degli oggetti CheckBox.In the Form1 constructor, after the call to InitializeComponent, create an ActionBlock<TInput> object that toggles the state of CheckBox objects.

    // Create an ActionBlock<CheckBox> object that toggles the state
    // of CheckBox objects.
    // Specifying the current synchronization context enables the 
    // action to run on the user-interface thread.
    var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
    {
       checkBox.Checked = !checkBox.Checked;
    }, 
    new ExecutionDataflowBlockOptions
    {
       TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
    });
    
       ' Create an ActionBlock<CheckBox> object that toggles the state
       ' of CheckBox objects.
       ' Specifying the current synchronization context enables the 
       ' action to run on the user-interface thread.
    Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
    
  5. Nel costruttore Form1 creare un oggetto ConcurrentExclusiveSchedulerPair e quattro oggetti ActionBlock<TInput>, un oggetto ActionBlock<TInput> per ogni oggetto CheckBox.In the Form1 constructor, create a ConcurrentExclusiveSchedulerPair object and four ActionBlock<TInput> objects, one ActionBlock<TInput> object for each CheckBox object. Per ogni oggetto ActionBlock<TInput>, specificare un oggetto ExecutionDataflowBlockOptions con la proprietà TaskScheduler impostata sulla proprietà ConcurrentScheduler per i lettori e la proprietà ExclusiveScheduler per il writer.For each ActionBlock<TInput> object, specify a ExecutionDataflowBlockOptions object that has the TaskScheduler property set to the ConcurrentScheduler property for the readers, and the ExclusiveScheduler property for the writer.

    // Create a ConcurrentExclusiveSchedulerPair object.
    // Readers will run on the concurrent part of the scheduler pair.
    // The writer will run on the exclusive part of the scheduler pair.
    var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();
    
    // Create an ActionBlock<int> object for each reader CheckBox object.
    // Each ActionBlock<int> object represents an action that can read 
    // from a resource in parallel to other readers.
    // Specifying the concurrent part of the scheduler pair enables the 
    // reader to run in parallel to other actions that are managed by 
    // that scheduler.
    var readerActions = 
       from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
       select new ActionBlock<int>(milliseconds =>
       {
          // Toggle the check box to the checked state.
          toggleCheckBox.Post(checkBox);
    
          // Perform the read action. For demonstration, suspend the current
          // thread to simulate a lengthy read operation.
          Thread.Sleep(milliseconds);
    
          // Toggle the check box to the unchecked state.
          toggleCheckBox.Post(checkBox);
       },
       new ExecutionDataflowBlockOptions
       {
          TaskScheduler = taskSchedulerPair.ConcurrentScheduler
       });
    
    // Create an ActionBlock<int> object for the writer CheckBox object.
    // This ActionBlock<int> object represents an action that writes to 
    // a resource, but cannot run in parallel to readers.
    // Specifying the exclusive part of the scheduler pair enables the 
    // writer to run in exclusively with respect to other actions that are 
    // managed by the scheduler pair.
    var writerAction = new ActionBlock<int>(milliseconds =>
    {
       // Toggle the check box to the checked state.
       toggleCheckBox.Post(checkBox4);
    
       // Perform the write action. For demonstration, suspend the current
       // thread to simulate a lengthy write operation.
       Thread.Sleep(milliseconds);
    
       // Toggle the check box to the unchecked state.
       toggleCheckBox.Post(checkBox4);
    },
    new ExecutionDataflowBlockOptions
    {
       TaskScheduler = taskSchedulerPair.ExclusiveScheduler
    });
    
    // Link the broadcaster to each reader and writer block.
    // The BroadcastBlock<T> class propagates values that it 
    // receives to all connected targets.
    foreach (var readerAction in readerActions)
    {
       broadcaster.LinkTo(readerAction);
    }
    broadcaster.LinkTo(writerAction);
    
    ' Create a ConcurrentExclusiveSchedulerPair object.
    ' Readers will run on the concurrent part of the scheduler pair.
    ' The writer will run on the exclusive part of the scheduler pair.
    Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()
    
    ' Create an ActionBlock<int> object for each reader CheckBox object.
    ' Each ActionBlock<int> object represents an action that can read 
    ' from a resource in parallel to other readers.
    ' Specifying the concurrent part of the scheduler pair enables the 
    ' reader to run in parallel to other actions that are managed by 
    ' that scheduler.
    Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
        Select New ActionBlock(Of Integer)(Sub(milliseconds)
            ' Toggle the check box to the checked state.
            ' Perform the read action. For demonstration, suspend the current
            ' thread to simulate a lengthy read operation.
            ' Toggle the check box to the unchecked state.
            toggleCheckBox.Post(checkBox)
            Thread.Sleep(milliseconds)
            toggleCheckBox.Post(checkBox)
        End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})
    
    ' Create an ActionBlock<int> object for the writer CheckBox object.
    ' This ActionBlock<int> object represents an action that writes to 
    ' a resource, but cannot run in parallel to readers.
    ' Specifying the exclusive part of the scheduler pair enables the 
    ' writer to run in exclusively with respect to other actions that are 
    ' managed by the scheduler pair.
    Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
        ' Toggle the check box to the checked state.
        ' Perform the write action. For demonstration, suspend the current
        ' thread to simulate a lengthy write operation.
        ' Toggle the check box to the unchecked state.
        toggleCheckBox.Post(checkBox4)
        Thread.Sleep(milliseconds)
        toggleCheckBox.Post(checkBox4)
    End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})
    
    ' Link the broadcaster to each reader and writer block.
    ' The BroadcastBlock<T> class propagates values that it 
    ' receives to all connected targets.
    For Each readerAction In readerActions
        broadcaster.LinkTo(readerAction)
    Next readerAction
    broadcaster.LinkTo(writerAction)
    
  6. Nel costruttore Form1 avviare l'oggetto Timer.In the Form1 constructor, start the Timer object.

    // Start the timer.
    timer1.Start();
    
    ' Start the timer.
    timer1.Start()
    
  7. Nella finestra di progettazione del form per il form principale creare un gestore eventi per l'evento Tick per il timer.On the form designer for the main form, create an event handler for the Tick event for the timer.

  8. Implementare l'evento Tick per il timer.Implement the Tick event for the timer.

    // Event handler for the timer.
    private void timer1_Tick(object sender, EventArgs e)
    {
       // Post a value to the broadcaster. The broadcaster
       // sends this message to each target. 
       broadcaster.Post(1000);
    }
    
    ' Event handler for the timer.
    Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
        ' Post a value to the broadcaster. The broadcaster
        ' sends this message to each target. 
        broadcaster.Post(1000)
    End Sub
    

Poiché il blocco di flussi di dati toggleCheckBox viene utilizzato nell'interfaccia utente, è importante che questa azione si verifichi nel thread dell'interfaccia utente.Because the toggleCheckBox dataflow block acts on the user interface, it is important that this action occur on the user-interface thread. A tale scopo, durante la costruzione questo oggetto fornisce un oggetto ExecutionDataflowBlockOptions con la proprietà TaskScheduler impostata su TaskScheduler.FromCurrentSynchronizationContext.To accomplish this, during construction this object provides a ExecutionDataflowBlockOptions object that has the TaskScheduler property set to TaskScheduler.FromCurrentSynchronizationContext. Tramite il metodo FromCurrentSynchronizationContext viene creato un oggetto TaskScheduler mediante il quale viene eseguito il lavoro nel contesto di sincronizzazione corrente.The FromCurrentSynchronizationContext method creates a TaskScheduler object that performs work on the current synchronization context. Poiché il costruttore Form1 viene chiamato dal thread dell'interfaccia utente, l'azione per il blocco di flussi di dati toggleCheckBox viene eseguita anche nel thread dell'interfaccia utente.Because the Form1 constructor is called from the user-interface thread, the action for the toggleCheckBox dataflow block also runs on the user-interface thread.

In questo esempio viene inoltre utilizzata la classe ConcurrentExclusiveSchedulerPair per consentire ad alcuni blocchi di flussi di dati di agire simultaneamente e a un altro blocco di flussi di dati di agire in modo esclusivo rispetto a tutti gli altri blocchi di flussi di dati in esecuzione nello stesso oggetto ConcurrentExclusiveSchedulerPair.This example also uses the ConcurrentExclusiveSchedulerPair class to enable some dataflow blocks to act concurrently, and another dataflow block to act exclusive with respect to all other dataflow blocks that run on the same ConcurrentExclusiveSchedulerPair object. Questa tecnica è utile quando da parte di più blocchi di flussi di dati viene condivisa una risorsa mentre altri richiedono l'accesso esclusivo a quest'ultima, poiché viene eliminata la necessità di sincronizzare manualmente l'accesso alla risorsa in questione.This technique is useful when multiple dataflow blocks share a resource and some require exclusive access to that resource, because it eliminates the requirement to manually synchronize access to that resource. L'eliminazione della sincronizzazione manuale può rendere il codice più efficiente.The elimination of manual synchronization can make code more efficient.

EsempioExample

L'esempio seguente illustra il codice completo per Form1.cs (Form1.vb per Visual Basic).The following example shows the complete code for Form1.cs (Form1.vb for Visual Basic).

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using System.Windows.Forms;

namespace WriterReadersWinForms
{
   public partial class Form1 : Form
   {
      // Broadcasts values to an ActionBlock<int> object that is associated
      // with each check box.
      BroadcastBlock<int> broadcaster = new BroadcastBlock<int>(null);

      public Form1()
      {         
         InitializeComponent();

         // Create an ActionBlock<CheckBox> object that toggles the state
         // of CheckBox objects.
         // Specifying the current synchronization context enables the 
         // action to run on the user-interface thread.
         var toggleCheckBox = new ActionBlock<CheckBox>(checkBox =>
         {
            checkBox.Checked = !checkBox.Checked;
         }, 
         new ExecutionDataflowBlockOptions
         {
            TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
         });

         // Create a ConcurrentExclusiveSchedulerPair object.
         // Readers will run on the concurrent part of the scheduler pair.
         // The writer will run on the exclusive part of the scheduler pair.
         var taskSchedulerPair = new ConcurrentExclusiveSchedulerPair();

         // Create an ActionBlock<int> object for each reader CheckBox object.
         // Each ActionBlock<int> object represents an action that can read 
         // from a resource in parallel to other readers.
         // Specifying the concurrent part of the scheduler pair enables the 
         // reader to run in parallel to other actions that are managed by 
         // that scheduler.
         var readerActions = 
            from checkBox in new CheckBox[] {checkBox1, checkBox2, checkBox3}
            select new ActionBlock<int>(milliseconds =>
            {
               // Toggle the check box to the checked state.
               toggleCheckBox.Post(checkBox);

               // Perform the read action. For demonstration, suspend the current
               // thread to simulate a lengthy read operation.
               Thread.Sleep(milliseconds);

               // Toggle the check box to the unchecked state.
               toggleCheckBox.Post(checkBox);
            },
            new ExecutionDataflowBlockOptions
            {
               TaskScheduler = taskSchedulerPair.ConcurrentScheduler
            });

         // Create an ActionBlock<int> object for the writer CheckBox object.
         // This ActionBlock<int> object represents an action that writes to 
         // a resource, but cannot run in parallel to readers.
         // Specifying the exclusive part of the scheduler pair enables the 
         // writer to run in exclusively with respect to other actions that are 
         // managed by the scheduler pair.
         var writerAction = new ActionBlock<int>(milliseconds =>
         {
            // Toggle the check box to the checked state.
            toggleCheckBox.Post(checkBox4);

            // Perform the write action. For demonstration, suspend the current
            // thread to simulate a lengthy write operation.
            Thread.Sleep(milliseconds);

            // Toggle the check box to the unchecked state.
            toggleCheckBox.Post(checkBox4);
         },
         new ExecutionDataflowBlockOptions
         {
            TaskScheduler = taskSchedulerPair.ExclusiveScheduler
         });

         // Link the broadcaster to each reader and writer block.
         // The BroadcastBlock<T> class propagates values that it 
         // receives to all connected targets.
         foreach (var readerAction in readerActions)
         {
            broadcaster.LinkTo(readerAction);
         }
         broadcaster.LinkTo(writerAction);

         // Start the timer.
         timer1.Start();
      }

      // Event handler for the timer.
      private void timer1_Tick(object sender, EventArgs e)
      {
         // Post a value to the broadcaster. The broadcaster
         // sends this message to each target. 
         broadcaster.Post(1000);
      }
   }
}
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Threading.Tasks.Dataflow

Namespace WriterReadersWinForms
    Partial Public Class Form1
        Inherits Form
        ' Broadcasts values to an ActionBlock<int> object that is associated
        ' with each check box.
        Private broadcaster As New BroadcastBlock(Of Integer)(Nothing)

        Public Sub New()
            InitializeComponent()

            ' Create an ActionBlock<CheckBox> object that toggles the state
            ' of CheckBox objects.
            ' Specifying the current synchronization context enables the 
            ' action to run on the user-interface thread.
         Dim toggleCheckBox = New ActionBlock(Of CheckBox)(Sub(checkBox) checkBox.Checked = Not checkBox.Checked, New ExecutionDataflowBlockOptions With {.TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})

            ' Create a ConcurrentExclusiveSchedulerPair object.
            ' Readers will run on the concurrent part of the scheduler pair.
            ' The writer will run on the exclusive part of the scheduler pair.
            Dim taskSchedulerPair = New ConcurrentExclusiveSchedulerPair()

            ' Create an ActionBlock<int> object for each reader CheckBox object.
            ' Each ActionBlock<int> object represents an action that can read 
            ' from a resource in parallel to other readers.
            ' Specifying the concurrent part of the scheduler pair enables the 
            ' reader to run in parallel to other actions that are managed by 
            ' that scheduler.
            Dim readerActions = From checkBox In New CheckBox() {checkBox1, checkBox2, checkBox3} _
                Select New ActionBlock(Of Integer)(Sub(milliseconds)
                    ' Toggle the check box to the checked state.
                    ' Perform the read action. For demonstration, suspend the current
                    ' thread to simulate a lengthy read operation.
                    ' Toggle the check box to the unchecked state.
                    toggleCheckBox.Post(checkBox)
                    Thread.Sleep(milliseconds)
                    toggleCheckBox.Post(checkBox)
                End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ConcurrentScheduler})

            ' Create an ActionBlock<int> object for the writer CheckBox object.
            ' This ActionBlock<int> object represents an action that writes to 
            ' a resource, but cannot run in parallel to readers.
            ' Specifying the exclusive part of the scheduler pair enables the 
            ' writer to run in exclusively with respect to other actions that are 
            ' managed by the scheduler pair.
            Dim writerAction = New ActionBlock(Of Integer)(Sub(milliseconds)
                ' Toggle the check box to the checked state.
                ' Perform the write action. For demonstration, suspend the current
                ' thread to simulate a lengthy write operation.
                ' Toggle the check box to the unchecked state.
                toggleCheckBox.Post(checkBox4)
                Thread.Sleep(milliseconds)
                toggleCheckBox.Post(checkBox4)
            End Sub, New ExecutionDataflowBlockOptions With {.TaskScheduler = taskSchedulerPair.ExclusiveScheduler})

            ' Link the broadcaster to each reader and writer block.
            ' The BroadcastBlock<T> class propagates values that it 
            ' receives to all connected targets.
            For Each readerAction In readerActions
                broadcaster.LinkTo(readerAction)
            Next readerAction
            broadcaster.LinkTo(writerAction)

            ' Start the timer.
            timer1.Start()
        End Sub

        ' Event handler for the timer.
        Private Sub timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles timer1.Tick
            ' Post a value to the broadcaster. The broadcaster
            ' sends this message to each target. 
            broadcaster.Post(1000)
        End Sub
    End Class
End Namespace

Vedere ancheSee also