Programmazione asincrona basata su attivitàTask-based Asynchronous Programming

La libreria Task Parallel Library (TPL) si basa sul concetto di attività, che rappresenta un'operazione asincrona.The Task Parallel Library (TPL) is based on the concept of a task, which represents an asynchronous operation. Per certi versi, un'attività è analoga a un thread o a un elemento di lavoro ThreadPool, ma a un livello più generale di astrazione.In some ways, a task resembles a thread or ThreadPool work item, but at a higher level of abstraction. L'espressione parallelismo delle attività fa riferimento a una o più attività indipendenti eseguite contemporaneamente.The term task parallelism refers to one or more independent tasks running concurrently. Le attività forniscono due vantaggi principali:Tasks provide two primary benefits:

  • Utilizzo più efficiente e scalabile delle risorse di sistema.More efficient and more scalable use of system resources.

    Ai fini del funzionamento, le attività vengono accodate a ThreadPool, che è stato migliorato con algoritmi che determinano e modificano il numero di thread e che ottimizzano la velocità effettiva grazie al bilanciamento del carico.Behind the scenes, tasks are queued to the ThreadPool, which has been enhanced with algorithms that determine and adjust to the number of threads and that provide load balancing to maximize throughput. In questo modo le attività diventano relativamente leggere ed è possibile crearne molte in modo da ottenere un parallelismo accurato.This makes tasks relatively lightweight, and you can create many of them to enable fine-grained parallelism.

  • Maggior controllo a livello di codice rispetto a quello ottenibile usando un thread o un elemento di lavoro.More programmatic control than is possible with a thread or work item.

    Le attività e il framework in cui esse sono inserite forniscono un ampio set di API che supportano varie funzionalità tra cui attesa, annullamento, continuazioni, gestione affidabile delle eccezioni, stato dettagliato e pianificazione personalizzata.Tasks and the framework built around them provide a rich set of APIs that support waiting, cancellation, continuations, robust exception handling, detailed status, custom scheduling, and more.

Per entrambi questi motivi, in .NET Framework TPL rappresenta l'API preferita per la scrittura di codice multithreading, asincrono e parallelo.For both of these reasons, in the .NET Framework, TPL is the preferred API for writing multi-threaded, asynchronous, and parallel code.

Creazione ed esecuzione implicite di attivitàCreating and running tasks implicitly

Il metodo Parallel.Invoke rappresenta un modo pratico per eseguire simultaneamente un numero qualsiasi di istruzioni arbitrarie.The Parallel.Invoke method provides a convenient way to run any number of arbitrary statements concurrently. Basta passare un delegato Action per ogni elemento di lavoro.Just pass in an Action delegate for each item of work. Il modo più semplice per creare questi delegati è usare le espressioni lambda.The easiest way to create these delegates is to use lambda expressions. L'espressione lambda può chiamare un metodo denominato o fornire il codice inline.The lambda expression can either call a named method or provide the code inline. Nell'esempio seguente viene mostrata una chiamata a Invoke di base che crea e avvia due attività in esecuzione simultanea.The following example shows a basic Invoke call that creates and starts two tasks that run concurrently. La prima attività è rappresentata da un'espressione lambda che chiama un metodo denominato DoSomeWork e la seconda attività è rappresentata da un'espressione lambda che chiama un metodo denominato DoSomeOtherWork.The first task is represented by a lambda expression that calls a method named DoSomeWork, and the second task is represented by a lambda expression that calls a method named DoSomeOtherWork.

Nota

Questa documentazione usa espressioni lambda per definire delegati in TPL.This documentation uses lambda expressions to define delegates in TPL. Se non si ha familiarità con le espressioni lambda in C# o Visual Basic, vedere Espressioni lambda in PLINQ e TPL.If you are not familiar with lambda expressions in C# or Visual Basic, see Lambda Expressions in PLINQ and TPL.

Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
Parallel.Invoke(Sub() DoSomeWork(), Sub() DoSomeOtherWork())

Nota

Il numero di istanze Task create automaticamente da Invoke non è necessariamente uguale al numero dei delegati forniti.The number of Task instances that are created behind the scenes by Invoke is not necessarily equal to the number of delegates that are provided. La libreria TPL può applicare varie ottimizzazioni, specialmente nel caso di un numero elevato di delegati.The TPL may employ various optimizations, especially with large numbers of delegates.

Per altre informazioni, vedere Procedura: utilizzare Parallel.Invoke per eseguire operazioni in parallelo.For more information, see How to: Use Parallel.Invoke to Execute Parallel Operations.

Per ottenere un controllo maggiore sull'esecuzione delle attività o per restituire un valore dall'attività, è necessario usare in modo più esplicito gli oggetti Task.For greater control over task execution or to return a value from the task, you have to work with Task objects more explicitly.

Creazione ed esecuzione esplicite di attivitàCreating and running tasks explicitly

Un'attività che non restituisce un valore è rappresentata dalla classe System.Threading.Tasks.Task.A task that does not return a value is represented by the System.Threading.Tasks.Task class. Un'attività che restituisce un valore viene rappresentata dalla classe System.Threading.Tasks.Task<TResult> che eredita da Task.A task that returns a value is represented by the System.Threading.Tasks.Task<TResult> class, which inherits from Task. L'oggetto attività gestisce i dettagli dell'infrastruttura e fornisce metodi e proprietà accessibili dal thread chiamante per tutta la durata dell'attività.The task object handles the infrastructure details and provides methods and properties that are accessible from the calling thread throughout the lifetime of the task. Ad esempio, è possibile accedere in qualsiasi momento alla proprietà Status di un'attività per determinare se è stata avviata, eseguita fino al completamento o annullata oppure se ha generato un'eccezione.For example, you can access the Status property of a task at any time to determine whether it has started running, ran to completion, was canceled, or has thrown an exception. Lo stato è rappresentato da un'enumerazione TaskStatus.The status is represented by a TaskStatus enumeration.

Quando si crea un'attività si assegna ad essa un delegato dell'utente che incapsula il codice che verrà eseguito dall'attività.When you create a task, you give it a user delegate that encapsulates the code that the task will execute. Il delegato può essere espresso come un delegato denominato, un metodo anonimo o un'espressione lambda.The delegate can be expressed as a named delegate, an anonymous method, or a lambda expression. Le espressioni lambda possono contenere una chiamata a un metodo denominato, come mostrato nell'esempio seguente.Lambda expressions can contain a call to a named method, as shown in the following example. Si noti che l'esempio include una chiamata al metodo Task.Wait per garantire che l'attività venga completata prima che termini l'applicazione in modalità console.Note that the example includes a call to the Task.Wait method to ensure that the task completes execution before the console mode application ends.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Thread.CurrentThread.Name = "Main";

      // Create a task and supply a user delegate by using a lambda expression. 
      Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
      // Start the task.
      taskA.Start();

      // Output a message from the calling thread.
      Console.WriteLine("Hello from thread '{0}'.", 
                        Thread.CurrentThread.Name);
      taskA.Wait();
   }
}
// The example displays output like the following:
//       Hello from thread 'Main'.
//       Hello from taskA.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
        Thread.CurrentThread.Name = "Main"
        
        ' Create a task and supply a user delegate by using a lambda expression. 
        Dim taskA = New Task(Sub() Console.WriteLine("Hello from taskA."))
        ' Start the task.
        taskA.Start()

        ' Output a message from the calling thread.
        Console.WriteLine("Hello from thread '{0}'.", 
                          Thread.CurrentThread.Name)
        taskA.Wait()
   End Sub
End Module
' The example displays output like the following:
'    Hello from thread 'Main'.
'    Hello from taskA.

È anche possibile usare i metodi Task.Run per creare e avviare un'attività in un'unica operazione.You can also use the Task.Run methods to create and start a task in one operation. Per gestire l'attività, i metodi Run usano l'utilità di pianificazione delle attività predefinita, indipendentemente dall'utilità di pianificazione associata al thread corrente.To manage the task, the Run methods use the default task scheduler, regardless of which task scheduler is associated with the current thread. I metodi Run rappresentano il modo preferito per creare e avviare le attività nei casi in cui non occorre un maggiore controllo sulla creazione e la pianificazione di attività.The Run methods are the preferred way to create and start tasks when more control over the creation and scheduling of the task is not needed.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Thread.CurrentThread.Name = "Main";

      // Define and run the task.
      Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

      // Output a message from the calling thread.
      Console.WriteLine("Hello from thread '{0}'.", 
                          Thread.CurrentThread.Name);
      taskA.Wait();
   }
}
// The example displays output like the following:
//       Hello from thread 'Main'.
//       Hello from taskA.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
        Thread.CurrentThread.Name = "Main"
        
        Dim taskA As Task = Task.Run(Sub() Console.WriteLine("Hello from taskA."))

        ' Output a message from the calling thread.
        Console.WriteLine("Hello from thread '{0}'.", 
                          Thread.CurrentThread.Name)
        taskA.Wait()
   End Sub
End Module
' The example displays output like the following:
'    Hello from thread 'Main'.
'    Hello from taskA.

È anche possibile usare il metodo TaskFactory.StartNew per creare e avviare un'attività in un'unica operazione.You can also use the TaskFactory.StartNew method to create and start a task in one operation. Usare questo metodo quando non occorre separare la creazione e la pianificazione ed è necessario avvalersi di opzioni aggiuntive di creazione delle attività o usare un'utilità di pianificazione specifica oppure quando si deve passare uno stato aggiuntivo all'attività tramite la proprietà AsyncState, come illustrato nell'esempio seguente.Use this method when creation and scheduling do not have to be separated and you require additional task creation options or the use of a specific scheduler, or when you need to pass additional state into the task through its AsyncState property, as shown in the following example.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Thread.CurrentThread.Name = "Main";

      // Better: Create and start the task in one operation. 
      Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));
      
      // Output a message from the calling thread.
      Console.WriteLine("Hello from thread '{0}'.", 
                        Thread.CurrentThread.Name);

      taskA.Wait();                  
   }
}
// The example displays output like the following:
//       Hello from thread 'Main'.
//       Hello from taskA.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Thread.CurrentThread.Name = "Main"
      
      ' Better: Create and start the task in one operation. 
      Dim taskA = Task.Factory.StartNew(Sub() Console.WriteLine("Hello from taskA."))
      
      ' Output a message from the calling thread.
      Console.WriteLine("Hello from thread '{0}'.", 
                        Thread.CurrentThread.Name)

      taskA.Wait()                  
   End Sub
End Module
' The example displays output like the following:
'       Hello from thread 'Main'.
'       Hello from taskA.

Task e Task<TResult> espongono ciascuna una proprietà statica Factory che restituisce un'istanza predefinita per TaskFactory, in modo che si possa chiamare il metodo come Task.Factory.StartNew().Task and Task<TResult> each expose a static Factory property that returns a default instance of TaskFactory, so that you can call the method as Task.Factory.StartNew(). Nell'esempio seguente, inoltre, poiché le attività sono di tipo System.Threading.Tasks.Task<TResult>, ognuna di esse presenta una proprietà Task<TResult>.Result pubblica che contiene il risultato del calcolo.Also, in the following example, because the tasks are of type System.Threading.Tasks.Task<TResult>, they each have a public Task<TResult>.Result property that contains the result of the computation. Le attività vengono eseguite in modo asincrono e possono essere completate in qualsiasi ordine.The tasks run asynchronously and may complete in any order. Se si accede alla proprietà Result prima che il calcolo venga completato, la proprietà blocca il thread chiamante finché il valore non è disponibile.If the Result property is accessed before the computation finishes, the property blocks the calling thread until the value is available.

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
        Task<Double>[] taskArray = { Task<Double>.Factory.StartNew(() => DoComputation(1.0)),
                                     Task<Double>.Factory.StartNew(() => DoComputation(100.0)), 
                                     Task<Double>.Factory.StartNew(() => DoComputation(1000.0)) };

        var results = new Double[taskArray.Length];
        Double sum = 0;
        
        for (int i = 0; i < taskArray.Length; i++) {
            results[i] = taskArray[i].Result;
            Console.Write("{0:N1} {1}", results[i], 
                              i == taskArray.Length - 1 ? "= " : "+ ");
            sum += results[i];
        }
        Console.WriteLine("{0:N1}", sum);
   }

   private static Double DoComputation(Double start)
   {
      Double sum = 0;
      for (var value = start; value <= start + 10; value += .1)
         sum += value;

      return sum; 
   }
}
// The example displays the following output:
//        606.0 + 10,605.0 + 100,495.0 = 111,706.0
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
        Dim taskArray() = { Task(Of Double).Factory.StartNew(Function() DoComputation(1.0)),
                            Task(Of Double).Factory.StartNew(Function() DoComputation(100.0)), 
                            Task(Of Double).Factory.StartNew(Function() DoComputation(1000.0)) }

        Dim results(taskArray.Length - 1) As Double
        Dim sum As Double
        
        For i As Integer = 0 To taskArray.Length - 1
            results(i) = taskArray(i).Result
            Console.Write("{0:N1} {1}", results(i), 
                              If(i = taskArray.Length - 1, "= ", "+ "))
            sum += results(i)
        Next
        Console.WriteLine("{0:N1}", sum)
   End Sub
   
   Private Function DoComputation(start As Double) As Double
      Dim sum As Double
      For value As Double = start To start + 10 Step .1
         sum += value
      Next
      Return sum 
   End Function
End Module
' The example displays the following output:
'       606.0 + 10,605.0 + 100,495.0 = 111,706.0

Per altre informazioni, vedere Procedura: Restituire un valore da un'attività.For more information, see How to: Return a Value from a Task.

Quando si usa un'espressione lambda per creare un delegato, si avrà accesso a tutte le variabili visibili in quel punto del codice sorgente.When you use a lambda expression to create a delegate, you have access to all the variables that are visible at that point in your source code. Tuttavia, in alcuni casi, in particolare all'interno dei cicli, un'espressione lambda non acquisisce la variabile come previsto.However, in some cases, most notably within loops, a lambda doesn't capture the variable as expected. Acquisisce solo il valore finale, non il valore mentre viene modificato dopo ogni iterazione.It only captures the final value, not the value as it mutates after each iteration. Nell'esempio che segue viene illustrato il problema.The following example illustrates the problem. Passa un contatore di cicli a un'espressione lambda che crea un'istanza di un oggetto CustomData e usa il contatore di cicli come identificatore dell'oggetto.It passes a loop counter to a lambda expression that instantiates a CustomData object and uses the loop counter as the object's identifier. Come indica l'output dell'esempio, ogni oggetto CustomData dispone di un identificatore identico.As the output from the example shows, each CustomData object has an identical identifier.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      // Create the task object by using an Action(Of Object) to pass in the loop
      // counter. This produces an unexpected result.
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj) => {
                                                 var data = new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks}; 
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                                 Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum);
                                               },
                                              i );
      }
      Task.WaitAll(taskArray);     
   }
}
// The example displays output like the following:
//       Task #10 created at 635116418427727841 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427727841 on thread #3.
//       Task #10 created at 635116418427747843 on thread #3.
//       Task #10 created at 635116418427747843 on thread #3.
//       Task #10 created at 635116418427737842 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      ' Create the task object by using an Action(Of Object) to pass in the loop
      ' counter. This produces an unexpected result.
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} 
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                                 Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum)
                                              End Sub,
                                              i )
      Next
      Task.WaitAll(taskArray)     
   End Sub
End Module
' The example displays output like the following:
'       Task #10 created at 635116418427727841 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427727841 on thread #3.
'       Task #10 created at 635116418427747843 on thread #3.
'       Task #10 created at 635116418427747843 on thread #3.
'       Task #10 created at 635116418427737842 on thread #4.

È possibile accedere al valore in ogni iterazione fornendo un oggetto stato a un'attività mediante il relativo costruttore.You can access the value on each iteration by providing a state object to a task through its constructor. Nell'esempio seguente viene modificato l'esempio precedente usando il contatore di cicli durante la creazione dell'oggetto CustomData, che, a sua volta, viene passato all'espressione lambda.The following example modifies the previous example by using the loop counter when creating the CustomData object, which, in turn, is passed to the lambda expression. Come indicato dall'output dell'esempio, ogni oggetto CustomData dispone ora di un identificatore univoco in base al valore del contatore di cicli al momento della creazione di un'istanza dell'oggetto.As the output from the example shows, each CustomData object now has a unique identifier based on the value of the loop counter at the time the object was instantiated.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      // Create the task object by using an Action(Of Object) to pass in custom data
      // to the Task constructor. This is useful when you need to capture outer variables
      // from within a loop. 
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj ) => {
                                                  CustomData data = obj as CustomData;
                                                  if (data == null) 
                                                     return;
                                     
                                                  data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                                  Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum);
                                               },
                                               new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks} );
      }
      Task.WaitAll(taskArray);     
   }
}
// The example displays output like the following:
//       Task #0 created at 635116412924597583 on thread #3.
//       Task #1 created at 635116412924607584 on thread #4.
//       Task #3 created at 635116412924607584 on thread #4.
//       Task #4 created at 635116412924607584 on thread #4.
//       Task #2 created at 635116412924607584 on thread #3.
//       Task #6 created at 635116412924607584 on thread #3.
//       Task #5 created at 635116412924607584 on thread #4.
//       Task #8 created at 635116412924607584 on thread #4.
//       Task #7 created at 635116412924607584 on thread #3.
//       Task #9 created at 635116412924607584 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      ' Create the task object by using an Action(Of Object) to pass in custom data
      ' to the Task constructor. This is useful when you need to capture outer variables
      ' from within a loop. 
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As CustomData = TryCast(obj, CustomData)
                                                 If data Is Nothing Then Return
                                     
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                                 Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum)
                                              End Sub,
                                              New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} )
      Next
      Task.WaitAll(taskArray)     
   End Sub
End Module
' The example displays output like the following:
'       Task #0 created at 635116412924597583 on thread #3.
'       Task #1 created at 635116412924607584 on thread #4.
'       Task #3 created at 635116412924607584 on thread #4.
'       Task #4 created at 635116412924607584 on thread #4.
'       Task #2 created at 635116412924607584 on thread #3.
'       Task #6 created at 635116412924607584 on thread #3.
'       Task #5 created at 635116412924607584 on thread #4.
'       Task #8 created at 635116412924607584 on thread #4.
'       Task #7 created at 635116412924607584 on thread #3.
'       Task #9 created at 635116412924607584 on thread #4.

Questo stato viene passato come argomento al delegato dell'attività ed è accessibile dall'oggetto attività tramite la proprietà Task.AsyncState.This state is passed as an argument to the task delegate, and it can be accessed from the task object by using the Task.AsyncState property. L'esempio seguente è una variante dell'esempio precedenteThe following example is a variation on the previous example. Usa la proprietà AsyncState per visualizzare informazioni sugli oggetti CustomData passati all'espressione lambda.It uses the AsyncState property to display information about the CustomData objects passed to the lambda expression.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj ) => {
                                                  CustomData data = obj as CustomData;
                                                  if (data == null) 
                                                     return;
                                     
                                                  data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                               },
                                               new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks} );
      }
      Task.WaitAll(taskArray);     
      foreach (var task in taskArray) {
         var data = task.AsyncState as CustomData;
         if (data != null)
            Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
                              data.Name, data.CreationTime, data.ThreadNum);
      }                     
   }
}
// The example displays output like the following:
//       Task #0 created at 635116412924597583 on thread #3.
//       Task #1 created at 635116412924607584 on thread #4.
//       Task #3 created at 635116412924607584 on thread #4.
//       Task #4 created at 635116412924607584 on thread #4.
//       Task #2 created at 635116412924607584 on thread #3.
//       Task #6 created at 635116412924607584 on thread #3.
//       Task #5 created at 635116412924607584 on thread #4.
//       Task #8 created at 635116412924607584 on thread #4.
//       Task #7 created at 635116412924607584 on thread #3.
//       Task #9 created at 635116412924607584 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As CustomData = TryCast(obj, CustomData)
                                                 If data Is Nothing Then Return
                                     
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                              End Sub,
                                              New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} )
      Next
      Task.WaitAll(taskArray)     

      For Each task In taskArray
         Dim data = TryCast(task.AsyncState, CustomData)
         If data IsNot Nothing Then
            Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
                              data.Name, data.CreationTime, data.ThreadNum)
         End If
      Next
   End Sub
End Module
' The example displays output like the following:
'    Task #0 created at 635116451245250515, ran on thread #3, RanToCompletion
'    Task #1 created at 635116451245270515, ran on thread #4, RanToCompletion
'    Task #2 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #3 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #4 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #5 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #6 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #7 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #8 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #9 created at 635116451245270515, ran on thread #3, RanToCompletion

ID attivitàTask ID

Ogni attività riceve un ID di tipo Integer con cui viene identificata in modo univoco in un dominio applicazione e a cui è possibile accedere tramite la proprietà Task.Id.Every task receives an integer ID that uniquely identifies it in an application domain and can be accessed by using the Task.Id property. Questo ID è utile per visualizzare informazioni sull'attività nelle finestre Stack in parallelo e Attività in parallelo del debugger di Visual Studio.The ID is useful for viewing task information in the Visual Studio debugger Parallel Stacks and Tasks windows. L'ID viene creato in modo differito, ovvero solo quando viene richiesto. Pertanto, un'attività può presentare un ID diverso ogni volta che viene eseguito il programma.The ID is lazily created, which means that it isn't created until it is requested; therefore, a task may have a different ID every time the program is run. Per altre informazioni su come visualizzare gli ID attività nel debugger, vedere Uso della finestra Attività e Utilizzo della finestra Stack in parallelo.For more information about how to view task IDs in the debugger, see Using the Tasks Window and Using the Parallel Stacks Window.

Opzioni di creazione delle attivitàTask Creation Options

La maggior parte delle API che creano attività genera overload che accettano un parametro TaskCreationOptions.Most APIs that create tasks provide overloads that accept a TaskCreationOptions parameter. Quando si specifica una di queste opzioni si indica all'utilità di pianificazione il modo in cui pianificare l'attività nel pool di thread.By specifying one of these options, you tell the task scheduler how to schedule the task on the thread pool. Nella tabella seguente sono elencate le varie opzioni di creazione delle attività.The following table lists the various task creation options.

Valore del parametro TaskCreationOptionsTaskCreationOptions parameter value DescrizioneDescription
None Valore predefinito quando non si specificano opzioni.The default when no option is specified. L'utilità di pianificazione usa le proprie regole euristiche predefinite per pianificare l'attività.The scheduler uses its default heuristics to schedule the task.
PreferFairness Specifica che l'attività deve essere pianificata in modo che le attività create prima abbiano più possibilità di essere eseguite prima delle attività create in un secondo momento.Specifies that the task should be scheduled so that tasks created sooner will be more likely to be executed sooner, and tasks created later will be more likely to execute later.
LongRunning Specifica che l'attività rappresenta un'operazione di lunga durata.Specifies that the task represents a long-running operation.
AttachedToParent Specifica che un'attività deve essere creata come figlio collegato dell'attività corrente, se esistente.Specifies that a task should be created as an attached child of the current task, if one exists. Per altre informazioni, vedere Attached and Detached Child Tasks (Attività figlio connesse e disconnesse).For more information, see Attached and Detached Child Tasks.
DenyChildAttach Specifica che se per un'attività interna è specificata l'opzione AttachedToParent, tale attività non diventerà un'attività figlio collegata.Specifies that if an inner task specifies the AttachedToParent option, that task will not become an attached child task.
HideScheduler Specifica che l'utilità di pianificazione delle attività create chiamando metodi come TaskFactory.StartNew o Task<TResult>.ContinueWith dall'interno di una particolare attività è l'utilità di pianificazione predefinita anziché l'utilità di pianificazione in cui questa attività è in esecuzione.Specifies that the task scheduler for tasks created by calling methods like TaskFactory.StartNew or Task<TResult>.ContinueWith from within a particular task is the default scheduler instead of the scheduler on which this task is running.

Le opzioni possono essere combinate usando un'operazione OR bit per bit.The options may be combined by using a bitwise OR operation. Nell'esempio seguente viene illustrata un'attività che presenta le opzioni LongRunning e PreferFairness.The following example shows a task that has the LongRunning and PreferFairness option.

var task3 = new Task(() => MyLongRunningMethod(),
                    TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
task3.Start();

Dim task3 = New Task(Sub() MyLongRunningMethod(),
                        TaskCreationOptions.LongRunning Or TaskCreationOptions.PreferFairness)
task3.Start()

Attività, thread e impostazioni culturaTasks, threads, and culture

Ogni thread dispone di impostazioni cultura nonché di impostazioni cultura dell'interfaccia utente associate e definite rispettivamente dalle proprietà Thread.CurrentCulture e Thread.CurrentUICulture.Each thread has an associated culture and UI culture, which is defined by the Thread.CurrentCulture and Thread.CurrentUICulture properties, respectively. Le impostazioni cultura di un thread vengono usate in operazioni quali formattazione, analisi, ordinamento e confronto di stringhe.A thread's culture is used in such operations as formatting, parsing, sorting, and string comparison. Le impostazioni cultura dell'interfaccia utente di un thread vengono usate per la ricerca delle risorse.A thread's UI culture is used in resource lookup. In genere, a meno che non sia possibile specificare delle impostazioni cultura predefinite per tutti i thread in un dominio applicazione usando le proprietà CultureInfo.DefaultThreadCurrentCulture e CultureInfo.DefaultThreadCurrentUICulture, le impostazioni cultura e le impostazioni cultura dell'interfaccia utente predefinite per un thread vengono definite dalle impostazioni cultura del sistema.Ordinarily, unless you specify a default culture for all the threads in an application domain by using the CultureInfo.DefaultThreadCurrentCulture and CultureInfo.DefaultThreadCurrentUICulture properties, the default culture and UI culture of a thread is defined by the system culture. Se si impostano le impostazioni cultura di un thread in modo esplicito e si avvia un nuovo thread, quest'ultimo non eredita le impostazioni cultura del thread chiamante, al contrario, le relative impostazioni cultura vengono definite da quelle del sistema.If you explicitly set a thread's culture and launch a new thread, the new thread does not inherit the culture of the calling thread; instead, its culture is the default system culture. Il modello di programmazione basato su attività per le applicazioni destinate alle versioni di .NET Framework precedenti a .NET Framework 4.6.NET Framework 4.6 è conforme a questa prassi.The task-based programming model for apps that target versions of the .NET Framework prior to .NET Framework 4.6.NET Framework 4.6 adhere to this practice.

Importante

Si noti che le impostazioni cultura del thread chiamante come parte del contesto di un'attività si applicano alle applicazioni che hanno come destinazione.NET Framework 4.6.NET Framework 4.6, non applicazioni che vengono eseguite in .NET Framework 4.6.NET Framework 4.6.Note that the calling thread's culture as part of a task's context applies to apps that target the .NET Framework 4.6.NET Framework 4.6, not apps that run under the .NET Framework 4.6.NET Framework 4.6. È possibile usare una versione specifica di .NET Framework come destinazione quando si crea il progetto in Visual Studio selezionando la versione nell'elenco a discesa nella parte superiore della finestra di dialogo Nuovo progetto oppure, esternamente a Visual Studio, è possibile usare l'attributo TargetFrameworkAttribute.You can target a particular version of the .NET Framework when you create your project in Visual Studio by selecting that version from the dropdown list at the top of the New Project dialog box, or outside of Visual Studio you can use the TargetFrameworkAttribute attribute. Per applicazioni destinate a versioni di .NET Framework precedenti alla .NET Framework 4.6.NET Framework 4.6, o non destinate a una versione specifica di .NET Framework, le impostazioni cultura di un'attività continuano a essere determinate dalle impostazioni cultura del thread in cui sono in esecuzione.For apps that target versions of the .NET Framework prior to the .NET Framework 4.6.NET Framework 4.6, or that do not target a specific version of the .NET Framework, a task's culture continues to be determined by the culture of the thread on which it runs.

A partire dalle applicazioni destinate a .NET Framework 4.6.NET Framework 4.6, le impostazioni cultura del thread chiamante viene ereditata da ogni attività, anche se l'attività viene eseguita in modo asincrono in un pool di thread.Starting with apps that target the .NET Framework 4.6.NET Framework 4.6, the calling thread's culture is inherited by each task, even if the task runs asynchronously on a thread pool thread.

Nell'esempio seguente viene illustrato questo concetto.The following example provides a simple illustration. Viene usato l'attributo TargetFrameworkAttribute per indicare .NET Framework 4.6.NET Framework 4.6 come destinazione e vengono modificate le impostazioni cultura correnti dell'applicazione in francese (Francia) o, se francese (Francia) corrisponde già alle impostazioni cultura correnti, inglese (Stati Uniti).It uses the TargetFrameworkAttribute attribute to target the .NET Framework 4.6.NET Framework 4.6 and changes the app's current culture to either French (France) or, if French (France) is already the current culture, English (United States). Viene quindi richiamato un delegato denominato formatDelegate che restituisce alcuni numeri formattati come valori di valuta nelle nuove impostazioni cultura.It then invokes a delegate named formatDelegate that returns some numbers formatted as currency values in the new culture. Si noti che, sia che il delegato venga eseguito come attività in modo sincrono o asincrono, esso restituirà il risultato previsto perché le impostazioni cultura del thread chiamante vengono ereditate dall'attività asincrona.Note that whether the delegate as a task either synchronously or asynchronously, it returns the expected result because the culture of the calling thread is inherited by the asynchronous task.

using System;
using System.Globalization;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;

[assembly:TargetFramework(".NETFramework,Version=v4.6")]

public class Example
{
   
   public static void Main()
   {
       decimal[] values = { 163025412.32m, 18905365.59m };
       string formatString = "C2";
       Func<String> formatDelegate = () => { string output = String.Format("Formatting using the {0} culture on thread {1}.\n",
                                                                           CultureInfo.CurrentCulture.Name,
                                                                           Thread.CurrentThread.ManagedThreadId);
                                             foreach (var value in values)
                                                output += String.Format("{0}   ", value.ToString(formatString));
                                                   
                                             output += Environment.NewLine;
                                             return output;
                                           };
       
       Console.WriteLine("The example is running on thread {0}", 
                         Thread.CurrentThread.ManagedThreadId);
       // Make the current culture different from the system culture.
       Console.WriteLine("The current culture is {0}", 
                         CultureInfo.CurrentCulture.Name);
       if (CultureInfo.CurrentCulture.Name == "fr-FR")
          Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
       else
          Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");

       Console.WriteLine("Changed the current culture to {0}.\n",
                         CultureInfo.CurrentCulture.Name);
       
       // Execute the delegate synchronously.
       Console.WriteLine("Executing the delegate synchronously:");
       Console.WriteLine(formatDelegate());
       
       // Call an async delegate to format the values using one format string.
       Console.WriteLine("Executing a task asynchronously:"); 
       var t1 = Task.Run(formatDelegate);
       Console.WriteLine(t1.Result);
       
       Console.WriteLine("Executing a task synchronously:");
       var t2 = new Task<String>(formatDelegate); 
       t2.RunSynchronously();
       Console.WriteLine(t2.Result);
   }
}
// The example displays the following output:
//         The example is running on thread 1
//         The current culture is en-US
//         Changed the current culture to fr-FR.
//
//         Executing the delegate synchronously:
//         Formatting using the fr-FR culture on thread 1.
//         163 025 412,32 €   18 905 365,59 €
//
//         Executing a task asynchronously:
//         Formatting using the fr-FR culture on thread 3.
//         163 025 412,32 €   18 905 365,59 €
//
//         Executing a task synchronously:
//         Formatting using the fr-FR culture on thread 1.
//         163 025 412,32 €   18 905 365,59 €
// If the TargetFrameworkAttribute statement is removed, the example
// displays the following output:
//          The example is running on thread 1
//          The current culture is en-US
//          Changed the current culture to fr-FR.
//
//          Executing the delegate synchronously:
//          Formatting using the fr-FR culture on thread 1.
//          163 025 412,32 €   18 905 365,59 €
//
//          Executing a task asynchronously:
//          Formatting using the en-US culture on thread 3.
//          $163,025,412.32   $18,905,365.59
//
//          Executing a task synchronously:
//          Formatting using the fr-FR culture on thread 1.
//          163 025 412,32 €   18 905 365,59 €
Imports System.Globalization
Imports System.Runtime.Versioning
Imports System.Threading
Imports System.Threading.Tasks

<Assembly:TargetFramework(".NETFramework,Version=v4.6")>

Module Example
   Public Sub Main()
       Dim values() As Decimal = { 163025412.32d, 18905365.59d }
       Dim formatString As String = "C2"
       Dim formatDelegate As Func(Of String) = Function()
                                                  Dim output As String = String.Format("Formatting using the {0} culture on thread {1}.",
                                                                                       CultureInfo.CurrentCulture.Name,
                                                                                       Thread.CurrentThread.ManagedThreadId)
                                                  output += Environment.NewLine
                                                  For Each value In values
                                                     output += String.Format("{0}   ", value.ToString(formatString))
                                                  Next 
                                                  output += Environment.NewLine
                                                  Return output
                                               End Function
       
       Console.WriteLine("The example is running on thread {0}", 
                         Thread.CurrentThread.ManagedThreadId)
       ' Make the current culture different from the system culture.
       Console.WriteLine("The current culture is {0}", 
                         CultureInfo.CurrentCulture.Name)
       If CultureInfo.CurrentCulture.Name = "fr-FR" Then
          Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")
       Else
          Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR")
       End If
       Console.WriteLine("Changed the current culture to {0}.",
                         CultureInfo.CurrentCulture.Name)
       Console.WriteLine()                  
       
       ' Execute the delegate synchronously.
       Console.WriteLine("Executing the delegate synchronously:")
       Console.WriteLine(formatDelegate())
       
       ' Call an async delegate to format the values using one format string.
       Console.WriteLine("Executing a task asynchronously:") 
       Dim t1 = Task.Run(formatDelegate)
       Console.WriteLine(t1.Result)
       
       Console.WriteLine("Executing a task synchronously:")
       Dim t2 = New Task(Of String)(formatDelegate) 
       t2.RunSynchronously()
       Console.WriteLine(t2.Result)
   End Sub
End Module
' The example displays the following output:
'          The example is running on thread 1
'          The current culture is en-US
'          Changed the current culture to fr-FR.
'
'          Executing the delegate synchronously:
'          Formatting Imports the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €
'
'          Executing a task asynchronously:
'          Formatting Imports the fr-FR culture on thread 3.
'          163 025 412,32 €   18 905 365,59 €
'
'          Executing a task synchronously:
'          Formatting Imports the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €
' If the TargetFrameworkAttribute statement is removed, the example
' displays the following output:
'          The example is running on thread 1
'          The current culture is en-US
'          Changed the current culture to fr-FR.
'
'          Executing the delegate synchronously:
'          Formatting using the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €
'
'          Executing a task asynchronously:
'          Formatting using the en-US culture on thread 3.
'          $163,025,412.32   $18,905,365.59
'
'          Executing a task synchronously:
'          Formatting using the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €

Se si usa Visual Studio, è possibile omettere l'attributo TargetFrameworkAttribute e selezionare invece .NET Framework 4.6 come destinazione quando si crea il progetto nella finestra di dialogo Nuovo progetto.If you are using Visual Studio, you can omit the TargetFrameworkAttribute attribute and instead select the .NET Framework 4.6 as the target when you create the project in the New Project dialog.

Per ottenere un output che rifletta il comportamento delle app che hanno come destinazione versioni di .NET Framework precedenti alla .NET Framework 4.6.NET Framework 4.6, rimuovere l'attributo TargetFrameworkAttribute dal codice sorgente.For output that reflects the behavior of apps the target versions of the .NET Framework prior to .NET Framework 4.6.NET Framework 4.6, remove the TargetFrameworkAttribute attribute from the source code. L'output rifletterà le convenzioni di formattazione delle impostazioni cultura di sistema predefinite e non di quelle del thread chiamante.The output will reflect the formatting conventions of the default system culture, not the culture of the calling thread.

Per altre informazioni sulle attività asincrone e sulle impostazioni cultura, vedere la sezione dedicata alle impostazioni cultura e alle operazioni asincrone basate sulle attività nell'argomento dedicato alla classe CultureInfo.For more information on asynchronous tasks and culture, see the "Culture and asynchronous task-based operations" section in the CultureInfo topic.

Creazione delle continuazioni di attivitàCreating task continuations

I metodi Task.ContinueWith e Task<TResult>.ContinueWith consentono di specificare un'attività da avviare al termine dell'attività precedente.The Task.ContinueWith and Task<TResult>.ContinueWith methods let you specify a task to start when the antecedent task finishes. Al delegato dell'attività di continuazione viene passato un riferimento all'attività precedente in modo da poter esaminare lo stato dell'attività precedente e, recuperando il valore della proprietà Task<TResult>.Result, usare l'output dell'attività precedente come input per la continuazione.The delegate of the continuation task is passed a reference to the antecedent task so that it can examine the antecedent task's status and, by retrieving the value of the Task<TResult>.Result property, can use the output of the antecedent as input for the continuation.

Nell'esempio seguente l'attività getData viene avviata da una chiamata al metodo TaskFactory.StartNew<TResult>(Func<TResult>).In the following example, the getData task is started by a call to the TaskFactory.StartNew<TResult>(Func<TResult>) method. L'attività processData viene avviata automaticamente quando termina getData e displayData viene avviata quando termina processData.The processData task is started automatically when getData finishes, and displayData is started when processData finishes. getData produce una matrice di tipo Integer accessibile da parte dell'attività processData tramite la proprietà getData dell'attività Task<TResult>.Result.getData produces an integer array, which is accessible to the processData task through the getData task's Task<TResult>.Result property. L'attività processData elabora la matrice e restituisce un risultato il cui tipo è dedotto dal tipo restituito dell'espressione lambda passata al metodo Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>).The processData task processes that array and returns a result whose type is inferred from the return type of the lambda expression passed to the Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>) method. L'attività displayData viene eseguita automaticamente quando termina processData e l'oggetto Tuple<T1,T2,T3> restituito dall'espressione lambda processData è accessibile da parte dell'attività displayData tramite la proprietà processData dell'attività Task<TResult>.Result.The displayData task executes automatically when processData finishes, and the Tuple<T1,T2,T3> object returned by the processData lambda expression is accessible to the displayData task through the processData task's Task<TResult>.Result property. L'attività displayData accetta i risultati dell'attività processData e produce un risultato il cui tipo viene dedotto in modo simile e che viene reso disponibile al programma nella proprietà Result.The displayData task takes the result of the processData task and produces a result whose type is inferred in a similar manner and which is made available to the program in the Result property.

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {                         
      var getData = Task.Factory.StartNew(() => { 
                                             Random rnd = new Random(); 
                                             int[] values = new int[100];
                                             for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)
                                                values[ctr] = rnd.Next();

                                             return values;
                                          } );  
      var processData = getData.ContinueWith((x) => {
                                                int n = x.Result.Length;
                                                long sum = 0;
                                                double mean;
                                  
                                                for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)
                                                   sum += x.Result[ctr];

                                                mean = sum / (double) n;
                                                return Tuple.Create(n, sum, mean);
                                             } ); 
      var displayData = processData.ContinueWith((x) => {
                                                    return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                                         x.Result.Item1, x.Result.Item2, 
                                                                         x.Result.Item3);
                                                 } );                         
      Console.WriteLine(displayData.Result);
   }
}
// The example displays output similar to the following:
//    N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim getData = Task.Factory.StartNew(Function() 
                                             Dim rnd As New Random()
                                             Dim values(99) As Integer
                                             For ctr = 0 To values.GetUpperBound(0)
                                                values(ctr) = rnd.Next()
                                             Next
                                             Return values
                                          End Function)  
      Dim processData = getData.ContinueWith(Function(x)
                                                Dim n As Integer = x.Result.Length
                                                Dim sum As Long
                                                Dim mean As Double
                                  
                                                For ctr = 0 To x.Result.GetUpperBound(0)
                                                   sum += x.Result(ctr)
                                                Next
                                                mean = sum / n
                                                Return Tuple.Create(n, sum, mean)
                                             End Function) 
      Dim displayData = processData.ContinueWith(Function(x)
                                                    Return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                                         x.Result.Item1, x.Result.Item2, 
                                                                         x.Result.Item3)
                                                 End Function)                         
      Console.WriteLine(displayData.Result)
   End Sub                        
End Module
' The example displays output like the following:
'   N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82

Poiché Task.ContinueWith è un metodo di istanza, è possibile concatenare le chiamate al metodo anziché creare un'istanza di un oggetto Task<TResult> per ogni attività precedente.Because Task.ContinueWith is an instance method, you can chain method calls together instead of instantiating a Task<TResult> object for each antecedent task. Dal punto di vista funzionale, il seguente esempio è identico al precedente, eccetto per il fatto che unisce in una catena le chiamate al metodo Task.ContinueWith.The following example is functionally identical to the previous example, except that it chains together calls to the Task.ContinueWith method. Si noti che l'oggetto Task<TResult> restituito dalla catena di chiamate al metodo è l'attività di continuazione finale.Note that the Task<TResult> object returned by the chain of method calls is the final continuation task.

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {                         
      var displayData = Task.Factory.StartNew(() => { 
                                                 Random rnd = new Random(); 
                                                 int[] values = new int[100];
                                                 for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)
                                                    values[ctr] = rnd.Next();

                                                 return values;
                                              } ).  
                        ContinueWith((x) => {
                                        int n = x.Result.Length;
                                        long sum = 0;
                                        double mean;
                                  
                                        for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)
                                           sum += x.Result[ctr];

                                        mean = sum / (double) n;
                                        return Tuple.Create(n, sum, mean);
                                     } ). 
                        ContinueWith((x) => {
                                        return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                             x.Result.Item1, x.Result.Item2, 
                                                             x.Result.Item3);
                                     } );                         
      Console.WriteLine(displayData.Result);
   }
}
// The example displays output similar to the following:
//    N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim displayData = Task.Factory.StartNew(Function() 
                                                 Dim rnd As New Random()
                                                 Dim values(99) As Integer
                                                 For ctr = 0 To values.GetUpperBound(0)
                                                    values(ctr) = rnd.Next()
                                                 Next
                                                 Return values
                                              End Function). _  
                        ContinueWith(Function(x)
                                        Dim n As Integer = x.Result.Length
                                        Dim sum As Long
                                        Dim mean As Double
                                  
                                        For ctr = 0 To x.Result.GetUpperBound(0)
                                           sum += x.Result(ctr)
                                        Next
                                        mean = sum / n
                                        Return Tuple.Create(n, sum, mean)
                                     End Function). _ 
                        ContinueWith(Function(x)
                                        Return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                             x.Result.Item1, x.Result.Item2,  
                                                             x.Result.Item3)
                                     End Function)                         
      Console.WriteLine(displayData.Result)
   End Sub                        
End Module
' The example displays output like the following:
'   N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82

I metodi ContinueWhenAll e ContinueWhenAny consentono di continuare da più attività.The ContinueWhenAll and ContinueWhenAny methods enable you to continue from multiple tasks.

Per altre informazioni, vedere Concatenamento di attività tramite attività di continuazione.For more information, see Chaining Tasks by Using Continuation Tasks.

Creazione di attività figlio scollegateCreating detached child tasks

Quando il codice utente in esecuzione in un'attività crea una nuova attività e non specifica l'opzione AttachedToParent, la nuova attività non viene sincronizzata con l'attività padre in alcun modo particolare.When user code that is running in a task creates a new task and does not specify the AttachedToParent option, the new task is not synchronized with the parent task in any special way. Questo tipo di attività non sincronizzata è definito attività annidata scollegata o attività figlio scollegata.This type of non-synchronized task is called a detached nested task or detached child task. Nell'esempio seguente viene mostrata un'attività che crea un'unica attività figlio scollegata.The following example shows a task that creates one detached child task.

var outer = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Outer task beginning.");

    var child = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(5000000);
        Console.WriteLine("Detached task completed.");
    });

});

outer.Wait();
Console.WriteLine("Outer task completed.");
// The example displays the following output:
//    Outer task beginning.
//    Outer task completed.
//    Detached task completed.
Dim outer = Task.Factory.StartNew(Sub()
                                      Console.WriteLine("Outer task beginning.")
                                      Dim child = Task.Factory.StartNew(Sub()
                                                                            Thread.SpinWait(5000000)
                                                                            Console.WriteLine("Detached task completed.")
                                                                        End Sub)
                                  End Sub)
outer.Wait()
Console.WriteLine("Outer task completed.")
' The example displays the following output:
'     Outer task beginning.
'     Outer task completed.
'    Detached child completed.

Si noti che l'attività padre non attende il completamento dell'attività figlio scollegata.Note that the parent task does not wait for the detached child task to finish.

Creazione di attività figlioCreating child tasks

Quando il codice utente in esecuzione in un'attività crea un'attività con l'opzione AttachedToParent, la nuova attività è detta attività figlio collegata dell'attività padre.When user code that is running in a task creates a task with the AttachedToParent option, the new task is known as a attached child task of the parent task. È possibile usare l'opzione AttachedToParent per esprimere il parallelismo fra attività strutturato, poiché l'attività padre attende in modo implicito il completamento di tutte le attività figlio collegate.You can use the AttachedToParent option to express structured task parallelism, because the parent task implicitly waits for all attached child tasks to finish. Nell'esempio seguente viene mostrata un'attività padre che crea dieci attività figlio collegate.The following example shows a parent task that creates ten attached child tasks. Si noti che anche se nell'esempio viene chiamato il metodo Task.Wait per attendere il completamento dell'attività padre, non si deve esplicitamente attendere il completamento delle attività figlio collegate.Note that although the example calls the Task.Wait method to wait for the parent task to finish, it does not have to explicitly wait for the attached child tasks to complete.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      var parent = Task.Factory.StartNew(() => {
                      Console.WriteLine("Parent task beginning.");
                      for (int ctr = 0; ctr < 10; ctr++) {
                         int taskNo = ctr;
                         Task.Factory.StartNew((x) => {
                                                  Thread.SpinWait(5000000);
                                                  Console.WriteLine("Attached child #{0} completed.", 
                                                                    x);
                                               },
                                               taskNo, TaskCreationOptions.AttachedToParent);
                      }
                   });

      parent.Wait();
      Console.WriteLine("Parent task completed.");
   }
}
// The example displays output like the following:
//       Parent task beginning.
//       Attached child #9 completed.
//       Attached child #0 completed.
//       Attached child #8 completed.
//       Attached child #1 completed.
//       Attached child #7 completed.
//       Attached child #2 completed.
//       Attached child #6 completed.
//       Attached child #3 completed.
//       Attached child #5 completed.
//       Attached child #4 completed.
//       Parent task completed.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim parent = Task.Factory.StartNew(Sub()
                                            Console.WriteLine("Parent task beginning.")
                                            For ctr As Integer = 0 To 9
                                               Dim taskNo As Integer = ctr
                                               Task.Factory.StartNew(Sub(x)
                                                                        Thread.SpinWait(5000000)
                                                                        Console.WriteLine("Attached child #{0} completed.", 
                                                                                          x)
                                                                     End Sub,
                                                                     taskNo, TaskCreationOptions.AttachedToParent)
                                            Next
                                         End Sub)
      parent.Wait()
      Console.WriteLine("Parent task completed.")
   End Sub
End Module   
' The example displays output like the following:
'       Parent task beginning.
'       Attached child #9 completed.
'       Attached child #0 completed.
'       Attached child #8 completed.
'       Attached child #1 completed.
'       Attached child #7 completed.
'       Attached child #2 completed.
'       Attached child #6 completed.
'       Attached child #3 completed.
'       Attached child #5 completed.
'       Attached child #4 completed.
'       Parent task completed.

Un'attività padre può usare l'opzione TaskCreationOptions.DenyChildAttach per impedire che altre attività vengano collegate all'attività padre.A parent task can use the TaskCreationOptions.DenyChildAttach option to prevent other tasks from attaching to the parent task. Per altre informazioni, vedere Attached and Detached Child Tasks (Attività figlio connesse e disconnesse).For more information, see Attached and Detached Child Tasks.

Attesa del completamento delle attivitàWaiting for tasks to finish

I tipi System.Threading.Tasks.Task e System.Threading.Tasks.Task<TResult> forniscono vari overload dei metodi Task.Wait e System.Threading.Tasks.Task.Wait che consentono di attendere il completamento di un'attività.The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> types provide several overloads of the Task.Wait and System.Threading.Tasks.Task.Wait methods that enable you to wait for a task to finish. Sono inoltre disponibili overload dei metodi statici Task.WaitAll e Task.WaitAny che consentono di attendere il completamento di alcune o di tutte le attività di una matrice.In addition, overloads of the static Task.WaitAll and Task.WaitAny methods let you wait for any or all of an array of tasks to finish.

L'attesa del completamento di un'attività è in genere dovuta a uno dei motivi seguenti:Typically, you would wait for a task for one of these reasons:

  • Il thread principale dipende dal risultato finale calcolato da un'attività.The main thread depends on the final result computed by a task.

  • È necessario gestire le eccezioni eventualmente generate dall'attività.You have to handle exceptions that might be thrown from the task.

  • L'applicazione può terminare prima del completamento di tutte le attività.The application may terminate before all tasks have completed execution. Ad esempio, le applicazioni di console termineranno dopo l'esecuzione di tutto il codice sincrono in Main (il punto di ingresso dell'applicazione).For example, console applications will terminate as soon as all synchronous code in Main (the application entry point) has executed.

Nell'esempio seguente viene mostrato il modello di base che non prevede la gestione delle eccezioni.The following example shows the basic pattern that does not involve exception handling.

Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => MethodA()),
    Task.Factory.StartNew(() => MethodB()),
    Task.Factory.StartNew(() => MethodC())
};

//Block until all tasks complete.
Task.WaitAll(tasks);

// Continue on this thread...
Dim tasks() =
{
    Task.Factory.StartNew(Sub() MethodA()),
    Task.Factory.StartNew(Sub() MethodB()),
    Task.Factory.StartNew(Sub() MethodC())
}

' Block until all tasks complete.
Task.WaitAll(tasks)

' Continue on this thread...

Per un esempio che illustra la gestione delle eccezioni, vedere Gestione delle eccezioni.For an example that shows exception handling, see Exception Handling.

Alcuni overload consentono di specificare un timeout mentre altri accettano un oggetto CancellationToken aggiuntivo come parametro di input, in modo che l'attesa stessa possa essere annullata a livello di codice o in risposta a un input dell'utente.Some overloads let you specify a time-out, and others take an additional CancellationToken as an input parameter, so that the wait itself can be canceled either programmatically or in response to user input.

Quando si resta in attesa di un'attività, si attendono in modo implicito tutti i figli di tale attività creati tramite l'opzione TaskCreationOptions.AttachedToParent.When you wait for a task, you implicitly wait for all children of that task that were created by using the TaskCreationOptions.AttachedToParent option. L'oggetto Task.Wait restituisce immediatamente un valore se l'attività è già stata completata.Task.Wait returns immediately if the task has already completed. Qualsiasi eccezione generata da un'attività verrà generata da un metodo Task.Wait, anche se il metodo Task.Wait è stato chiamato dopo il completamento dell'attività.Any exceptions raised by a task will be thrown by a Task.Wait method, even if the Task.Wait method was called after the task completed.

Composizione di attivitàComposing tasks

Le classi Task e Task<TResult> forniscono numerosi metodi che possono agevolare la composizione di più attività per l'implementazione di modelli comuni e usare meglio le funzionalità di linguaggio asincrone fornite da C#, Visual Basic e F#.The Task and Task<TResult> classes provide several methods that can help you compose multiple tasks to implement common patterns and to better use the asynchronous language features that are provided by C#, Visual Basic, and F#. In questa sezione vengono descritti i metodi WhenAll, WhenAny, Delay e FromResult.This section describes the WhenAll, WhenAny, Delay, and FromResult methods.

Task.WhenAllTask.WhenAll

Il metodo Task.WhenAll attende in modo asincrono che terminino più oggetti Task o Task<TResult>.The Task.WhenAll method asynchronously waits for multiple Task or Task<TResult> objects to finish. Fornisce le versioni di overload che consentono di attendere i set di attività non uniformi.It provides overloaded versions that enable you to wait for non-uniform sets of tasks. Ad esempio, è possibile attendere il completamento di più oggetti Task e Task<TResult> da una chiamata al metodo.For example, you can wait for multiple Task and Task<TResult> objects to complete from one method call.

Task.WhenAnyTask.WhenAny

Il metodo Task.WhenAny attende in modo asincrono che termini uno degli oggetti Task o Task<TResult>.The Task.WhenAny method asynchronously waits for one of multiple Task or Task<TResult> objects to finish. Come nel metodo Task.WhenAll, questo metodo fornisce le versioni di overload che consentono di attendere i set di attività non uniformi.As in the Task.WhenAll method, this method provides overloaded versions that enable you to wait for non-uniform sets of tasks. Il metodo WhenAny è particolarmente utile nei seguenti scenari.The WhenAny method is especially useful in the following scenarios.

  • Operazioni ridondanti.Redundant operations. Si consideri un algoritmo o un'operazione eseguibile in molti modi.Consider an algorithm or operation that can be performed in many ways. È possibile usare il metodo WhenAny per selezionare l'operazione che termina per prima e quindi annullare le operazioni rimanenti.You can use the WhenAny method to select the operation that finishes first and then cancel the remaining operations.

  • Operazioni interfogliate.Interleaved operations. È possibile avviare più operazioni, le quali devono tutte essere completate e usare il metodo WhenAny per elaborare i risultati al termine di ogni operazione.You can start multiple operations that must all finish and use the WhenAny method to process results as each operation finishes. Al termine di un'operazione, è possibile avviare una o più attività aggiuntive.After one operation finishes, you can start one or more additional tasks.

  • Operazioni con limitazione.Throttled operations. È possibile usare il metodo WhenAny per estendere lo scenario precedente limitando il numero di operazioni simultanee.You can use the WhenAny method to extend the previous scenario by limiting the number of concurrent operations.

  • Operazioni scadute.Expired operations. È possibile usare il metodo WhenAny per scegliere tra una o più attività e un'attività che termina dopo un periodo specifico, ad esempio un'attività restituita dal metodo Delay.You can use the WhenAny method to select between one or more tasks and a task that finishes after a specific time, such as a task that is returned by the Delay method. Il metodo Delay è descritto nella sezione che segue.The Delay method is described in the following section.

Task.DelayTask.Delay

Il metodo Task.Delay produce un oggetto Task che viene completato allo scadere del tempo specificato.The Task.Delay method produces a Task object that finishes after the specified time. È possibile usare questo metodo per creare cicli che occasionalmente eseguono il polling dei dati, introducono timeout, ritardano la gestione dell'input utente per un tempo predeterminato e così via.You can use this method to build loops that occasionally poll for data, introduce time-outs, delay the handling of user input for a predetermined time, and so on.

Task(T).FromResultTask(T).FromResult

Tramite il metodo Task.FromResult, è possibile creare un oggetto Task<TResult> contenente un risultato precedentemente calcolato.By using the Task.FromResult method, you can create a Task<TResult> object that holds a pre-computed result. Questo metodo è utile quando si esegue un'operazione asincrona che restituisce un oggetto Task<TResult> e il risultato di tale oggetto Task<TResult> è già calcolato.This method is useful when you perform an asynchronous operation that returns a Task<TResult> object, and the result of that Task<TResult> object is already computed. Per un esempio che usa FromResult per recuperare i risultati delle operazioni di download asincrone contenuti in una cache, vedere Procedura: Creare attività precalcolate.For an example that uses FromResult to retrieve the results of asynchronous download operations that are held in a cache, see How to: Create Pre-Computed Tasks.

Gestione delle eccezioni nelle attivitàHandling exceptions in tasks

Quando un'attività genera una o più eccezioni, il sistema esegue il wrapping di queste ultime in un'eccezione AggregateException.When a task throws one or more exceptions, the exceptions are wrapped in an AggregateException exception. Tale eccezione viene ripropagata al thread che si unisce all'attività, ovvero in genere il thread che resta in attesa del completamento dell'attività o che accede alla proprietà Result.That exception is propagated back to the thread that joins with the task, which is typically the thread that is waiting for the task to finish or the thread that accesses the Result property. Questo comportamento serve a imporre i criteri di .NET Framework secondo cui tutte le eccezioni non gestite devono comportare per impostazione predefinita la terminazione del processo.This behavior serves to enforce the .NET Framework policy that all unhandled exceptions by default should terminate the process. Il codice che effettua la chiamata può gestire le eccezioni usando uno qualsiasi degli elementi seguenti in un blocco try/catch:The calling code can handle the exceptions by using any of the following in a try/catch block:

Anche il thread di unione può gestire le eccezioni. A tale scopo, deve accedere alla proprietà Exception prima che l'attività venga raccolta nel Garbage Collector.The joining thread can also handle exceptions by accessing the Exception property before the task is garbage-collected. L'accesso a questa proprietà impedisce all'eccezione non gestita di attivare il comportamento di propagazione delle eccezioni che termina il processo quando l'oggetto viene finalizzato.By accessing this property, you prevent the unhandled exception from triggering the exception propagation behavior that terminates the process when the object is finalized.

Per ulteriori informazioni sulle eccezioni e sulle attività, vedere Gestione delle eccezioni.For more information about exceptions and tasks, see Exception Handling.

Annullamento delle attivitàCanceling tasks

La classe Task supporta l'annullamento cooperativo ed è completamente integrata con le classi System.Threading.CancellationTokenSource e System.Threading.CancellationToken, che sono state introdotte in .NET Framework 4.The Task class supports cooperative cancellation and is fully integrated with the System.Threading.CancellationTokenSource and System.Threading.CancellationToken classes, which were introduced in the .NET Framework 4. Molti dei costruttori nella classe System.Threading.Tasks.Task accettano un oggetto CancellationToken come parametro di input.Many of the constructors in the System.Threading.Tasks.Task class take a CancellationToken object as an input parameter. Molti degli overload StartNew e Run includono anche un parametro CancellationToken.Many of the StartNew and Run overloads also include a CancellationToken parameter.

È possibile creare il token e inviare la richiesta di annullamento in un secondo momento tramite la classe CancellationTokenSource.You can create the token, and issue the cancellation request at some later time, by using the CancellationTokenSource class. Passare il token a Task come argomento. Inoltre, fare riferimento allo stesso token nel delegato dell'utente, che esegue le operazioni necessarie per rispondere a una richiesta di annullamento.Pass the token to the Task as an argument, and also reference the same token in your user delegate, which does the work of responding to a cancellation request.

Per altre informazioni, vedere Annullamento delle attività e Procedura: Annullare un'attività e i relativi figli.For more information, see Task Cancellation and How to: Cancel a Task and Its Children.

Classe TaskFactoryThe TaskFactory class

La classe TaskFactory fornisce metodi statici che incapsulano alcuni modelli comuni per la creazione e l'avvio di attività e di attività di continuazione.The TaskFactory class provides static methods that encapsulate some common patterns for creating and starting tasks and continuation tasks.

L'oggetto TaskFactory predefinito è accessibile come proprietà statica della classe Task o della classe Task<TResult>.The default TaskFactory can be accessed as a static property on the Task class or Task<TResult> class. È anche possibile creare direttamente un'istanza di TaskFactory e specificare varie opzioni che includono un oggetto CancellationToken, un'opzione TaskCreationOptions, un'opzione TaskContinuationOptions o un oggetto TaskScheduler.You can also instantiate a TaskFactory directly and specify various options that include a CancellationToken, a TaskCreationOptions option, a TaskContinuationOptions option, or a TaskScheduler. Tutte le opzioni specificate quando si crea la factory delle attività verranno applicate a tutte le attività create da tale factory, tranne nel caso in cui l'oggetto Task venga creato tramite l'enumerazione TaskCreationOptions. In tal caso, le opzioni dell'attività eseguono l'override di quelle della factory delle attività.Whatever options are specified when you create the task factory will be applied to all tasks that it creates, unless the Task is created by using the TaskCreationOptions enumeration, in which case the task's options override those of the task factory.

Attività senza delegatiTasks without delegates

In alcuni casi è necessario usare un oggetto Task per incapsulare un'operazione asincrona eseguita da un componente esterno anziché dal delegato dell'utente.In some cases, you may want to use a Task to encapsulate some asynchronous operation that is performed by an external component instead of your own user delegate. Se l'operazione si basa sul modello Begin/End del modello di programmazione asincrona, è possibile usare i metodi FromAsync.If the operation is based on the Asynchronous Programming Model Begin/End pattern, you can use the FromAsync methods. In caso contrario, è possibile usare l'oggetto TaskCompletionSource<TResult> per eseguire il wrapping dell'operazione in un'attività e in questo modo ottenere alcuni dei vantaggi della programmabilità di Task, ad esempio il supporto per la propagazione delle eccezioni e le continuazioni.If that is not the case, you can use the TaskCompletionSource<TResult> object to wrap the operation in a task and thereby gain some of the benefits of Task programmability, for example, support for exception propagation and continuations. Per altre informazioni, vedere TaskCompletionSource<TResult>.For more information, see TaskCompletionSource<TResult>.

Utilità di pianificazione personalizzateCustom schedulers

Per la maggior parte degli sviluppatori di applicazioni o librerie non occorre determinare il processore in cui è in esecuzione l'attività né come quest'ultima sincronizza il proprio lavoro con le altre attività o come viene pianificata in System.Threading.ThreadPool.Most application or library developers do not care which processor the task runs on, how it synchronizes its work with other tasks, or how it is scheduled on the System.Threading.ThreadPool. Tali sviluppatori richiedono soltanto che l'attività venga eseguita con la maggiore efficienza possibile nel computer host.They only require that it execute as efficiently as possible on the host computer. Se si richiede un controllo più accurato sui dettagli di pianificazione, la libreria Task Parallel Library (TPL) consente di configurare alcune impostazioni nell'utilità di pianificazione delle attività predefinita. Inoltre, tale libreria consente persino di fornire un'utilità di pianificazione personalizzata.If you require more fine-grained control over the scheduling details, the Task Parallel Library lets you configure some settings on the default task scheduler, and even lets you supply a custom scheduler. Per altre informazioni, vedere TaskScheduler.For more information, see TaskScheduler.

La libreria TPL presenta vari nuovi tipi pubblici che risultano utili sia negli scenari in parallelo sia in quelli sequenziali.The TPL has several new public types that are useful in both parallel and sequential scenarios. Fra questi sono incluse varie classi di raccolte thread-safe, veloci e scalabili nello spazio dei nomi System.Collections.Concurrent nonché molti nuovi tipi di sincronizzazione, ad esempio System.Threading.Semaphore e System.Threading.ManualResetEventSlim che sono più efficienti dei relativi predecessori per tipi specifici di carichi di lavoro.These include several thread-safe, fast and scalable collection classes in the System.Collections.Concurrent namespace, and several new synchronization types, for example, System.Threading.Semaphore and System.Threading.ManualResetEventSlim, which are more efficient than their predecessors for specific kinds of workloads. Altri nuovi tipi di .NET Framework 4, ad esempio System.Threading.Barrier e System.Threading.SpinLock, forniscono funzionalità non disponibili nelle versioni precedenti.Other new types in the .NET Framework 4, for example, System.Threading.Barrier and System.Threading.SpinLock, provide functionality that was not available in earlier releases. Per ulteriori informazioni, vedere Strutture di dati per la programmazione in parallelo.For more information, see Data Structures for Parallel Programming.

Tipi di attività personalizzatiCustom task types

È consigliabile non ereditare da System.Threading.Tasks.Task o System.Threading.Tasks.Task<TResult>.We recommend that you do not inherit from System.Threading.Tasks.Task or System.Threading.Tasks.Task<TResult>. È invece consigliabile usare la proprietà AsyncState per associare i dati o lo stato aggiuntivi a un oggetto Task o Task<TResult>.Instead, we recommend that you use the AsyncState property to associate additional data or state with a Task or Task<TResult> object. È anche possibile usare i metodi di estensione per estendere la funzionalità delle classi Task e Task<TResult>.You can also use extension methods to extend the functionality of the Task and Task<TResult> classes. Per altre informazioni sui metodi di estensione, vedere Metodi di estensione e Metodi di estensione.For more information about extension methods, see Extension Methods and Extension Methods.

Se è necessario ereditare da Task o Task<TResult>, non è possibile usare Run, Run o le classi System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult> o System.Threading.Tasks.TaskCompletionSource<TResult> per creare istanze del tipo di attività personalizzato, poiché questi meccanismi creano solo oggetti Task e Task<TResult>.If you must inherit from Task or Task<TResult>, you cannot use Run, Run, or the System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>, or System.Threading.Tasks.TaskCompletionSource<TResult> classes to create instances of your custom task type because these mechanisms create only Task and Task<TResult> objects. Non è inoltre possibile usare i meccanismi di continuazione dell'attività forniti da Task, Task<TResult> TaskFactory e TaskFactory<TResult> per creare istanze del tipo di attività personalizzato poiché anche questi meccanismi creano solo oggetti Task e Task<TResult>.In addition, you cannot use the task continuation mechanisms that are provided by Task, Task<TResult>, TaskFactory, and TaskFactory<TResult> to create instances of your custom task type because these mechanisms also create only Task and Task<TResult> objects.

TitoloTitle DescrizioneDescription
Concatenamento di attività tramite attività di continuazioneChaining Tasks by Using Continuation Tasks Viene descritto il funzionamento delle continuazioni.Describes how continuations work.
Attività figlio connesse e disconnesseAttached and Detached Child Tasks Viene descritta la differenza tra attività figlio collegate e scollegate.Describes the difference between attached and detached child tasks.
Annullamento delle attivitàTask Cancellation Viene descritto il supporto dell'annullamento, incorporato nell'oggetto Task.Describes the cancellation support that is built into the Task object.
Gestione delle eccezioniException Handling Viene descritto come vengono gestite le eccezioni su thread simultanei.Describes how exceptions on concurrent threads are handled.
Procedura: Usare parallel_invoke per eseguire operazioni in paralleloHow to: Use Parallel.Invoke to Execute Parallel Operations Viene descritto come usare Invoke.Describes how to use Invoke.
Procedura: Restituire un valore da un'attivitàHow to: Return a Value from a Task Viene descritto come restituire valori dalle attività.Describes how to return values from tasks.
Procedura: Annullare un'attività e i relativi figliHow to: Cancel a Task and Its Children Viene descritto come annullare le attività.Describes how to cancel tasks.
Procedura: Creare attività precalcolateHow to: Create Pre-Computed Tasks Viene descritto come usare il metodo Task.FromResult per recuperare i risultati delle operazioni di download asincrone contenuti in una cache.Describes how to use the Task.FromResult method to retrieve the results of asynchronous download operations that are held in a cache.
Procedura: Attraversare un albero binario con attività in paralleloHow to: Traverse a Binary Tree with Parallel Tasks Viene descritto come usare le attività per attraversare un albero binario.Describes how to use tasks to traverse a binary tree.
Procedura: annullare il wrapping di un'attività annidataHow to: Unwrap a Nested Task Viene illustrato come usare il metodo di estensione Unwrap.Demonstrates how to use the Unwrap extension method.
Parallelismo dei datiData Parallelism Viene descritto come usare For e ForEach per creare cicli paralleli su dati.Describes how to use For and ForEach to create parallel loops over data.
Programmazione parallelaParallel Programming Nodo di livello principale per la programmazione parallela di .NET Framework.Top level node for .NET Framework parallel programming.

Vedere ancheSee Also

Programmazione parallelaParallel Programming
Esempi di programmazione parallela con .NET FrameworkSamples for Parallel Programming with the .NET Framework