Programação assíncrona baseada em tarefasTask-based asynchronous programming

A TPL (Biblioteca de Paralelismo de Tarefas) é baseada no conceito de uma tarefa, que representa uma operação assíncrona.The Task Parallel Library (TPL) is based on the concept of a task, which represents an asynchronous operation. De certa forma, uma tarefa é semelhante a um thread ou a um item de trabalho ThreadPool, mas em um nível mais alto de abstração.In some ways, a task resembles a thread or ThreadPool work item, but at a higher level of abstraction. O termo paralelismo de tarefas refere-se a uma ou mais tarefas independentes que são executadas simultaneamente.The term task parallelism refers to one or more independent tasks running concurrently. As tarefas fornecem dois benefícios principais:Tasks provide two primary benefits:

  • Uso mais eficiente e mais dimensionável de recursos do sistema.More efficient and more scalable use of system resources.

    Nos bastidores, as tarefas são colocadas na fila ThreadPool, a qual foi aprimorada com algoritmos que determinam e se ajustam ao número de segmentos e que fornecem o balanceamento de carga para maximizar o rendimento.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. Isso torna as tarefas relativamente simples, e você pode criar muitas delas para habilitar um paralelismo refinado.This makes tasks relatively lightweight, and you can create many of them to enable fine-grained parallelism.

  • Controle mais programático do que é possível com um thread ou um item de trabalho.More programmatic control than is possible with a thread or work item.

    As tarefas e a estrutura criada em torno delas fornecem um rico conjunto de APIs que oferecem suporte a espera, cancelamentos, continuações, tratamento de exceções robusto, status detalhado, agendamento personalizado e mais.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.

Por esses motivos, no .NET Framework, a TPL é a API preferida para escrever código multithread, assíncrono e código paralelo.For both of these reasons, in the .NET Framework, TPL is the preferred API for writing multi-threaded, asynchronous, and parallel code.

Criando e executando tarefas de forma implícitaCreating and running tasks implicitly

O método Parallel.Invoke fornece uma maneira conveniente de executar simultaneamente um número qualquer de instruções arbitrárias.The Parallel.Invoke method provides a convenient way to run any number of arbitrary statements concurrently. Basta passar um delegado Action para cada item de trabalho.Just pass in an Action delegate for each item of work. A maneira mais fácil de criar esses delegados é usar expressões lambda.The easiest way to create these delegates is to use lambda expressions. A expressão lambda pode chamar um método chamado ou fornecer o código embutido.The lambda expression can either call a named method or provide the code inline. O exemplo a seguir mostra uma chamada Invoke básica que cria e inicia duas tarefas executadas simultaneamente.The following example shows a basic Invoke call that creates and starts two tasks that run concurrently. A primeira tarefa é representada por uma expressão lambda que chama um método denominado DoSomeWork. A segunda tarefa é representada por uma expressão lambda que chama um método denominado 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.

Observação

Esta documentação usa expressões lambda para definir delegados na TLP.This documentation uses lambda expressions to define delegates in TPL. Se você não estiver familiarizado com expressões lambda no C# ou no Visual Basic, veja Expressões lambda em 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())

Observação

O número de instâncias de Task que são criadas em segundo plano por Invoke não é necessariamente igual ao número de delegados que são fornecidos.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. A TPL pode usar várias otimizações, principalmente com números grandes de delegados.The TPL may employ various optimizations, especially with large numbers of delegates.

Para obter mais informações, consulte Como usar Parallel.Invoke para executar operações em paralelo.For more information, see How to: Use Parallel.Invoke to Execute Parallel Operations.

Para obter maior controle sobre a execução da tarefa ou para retornar um valor da tarefa, é necessário trabalhar com objetos Task de forma mais explícita.For greater control over task execution or to return a value from the task, you have to work with Task objects more explicitly.

Criando e executando tarefas de forma explícitaCreating and running tasks explicitly

Uma tarefa que não retorna um valor é representada pela classe System.Threading.Tasks.Task.A task that does not return a value is represented by the System.Threading.Tasks.Task class. Uma tarefa que retorna um valor é representada pela classe System.Threading.Tasks.Task<TResult>, a qual herda de Task.A task that returns a value is represented by the System.Threading.Tasks.Task<TResult> class, which inherits from Task. O objeto da tarefa lida com os detalhes da infraestrutura e fornece métodos e propriedades que são acessíveis a partir do segmento de chamada em todo o tempo de vida da tarefa.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. Por exemplo, você pode acessar a propriedade Status de uma tarefa a qualquer momento para determinar se ela começou a ser executada, se foi executada até a conclusão, se foi cancelada ou se uma exceção foi gerada.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. O status é representado por uma enumeração TaskStatus.The status is represented by a TaskStatus enumeration.

Quando você cria uma tarefa, fornece a ela um delegado de usuário que encapsula o código que a tarefa irá executar.When you create a task, you give it a user delegate that encapsulates the code that the task will execute. O delegado pode ser expresso como um delegado nomeado, um método anônimo ou uma expressão lambda.The delegate can be expressed as a named delegate, an anonymous method, or a lambda expression. As expressões lambda podem conter uma chamada para um método nomeado, conforme mostrado no exemplo a seguir.Lambda expressions can contain a call to a named method, as shown in the following example. Observe que o exemplo inclui uma chamada para o método Task.Wait para garantir que a tarefa termine a execução antes do aplicativo de modo console terminar.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.

Você também pode usar os métodos Task.Run para criar e iniciar uma tarefa em uma única operação.You can also use the Task.Run methods to create and start a task in one operation. Para gerenciar a tarefa, os métodos Run usam o agendador de tarefas padrão, independentemente de qual agendador de tarefas é associado ao segmento atual.To manage the task, the Run methods use the default task scheduler, regardless of which task scheduler is associated with the current thread. Os métodos Run são a maneira preferencial para criar e iniciar tarefas quando mais controle sobre a criação e o agendamento da tarefa não é necessário.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.

Você também pode usar o método TaskFactory.StartNew para criar e iniciar uma tarefa em uma operação.You can also use the TaskFactory.StartNew method to create and start a task in one operation. Use este método quando a criação e o agendamento não precisarem ser separados e você precisar de opções adicionais de criação de tarefas ou do uso de um agendador específico, ou ainda quando você precisar passar estado adicional na tarefa que você pode recuperar através da propriedade Task.AsyncState, conforme mostrado no exemplo a seguir.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 that you can retrieve through its Task.AsyncState property, as shown in the following example.

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

Task e Task<TResult> expõem uma propriedade Factory estática que retorna uma instância padrão de TaskFactory para que você possa chamar o método como 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(). Além disso, no exemplo a seguir, como as tarefas são do tipo System.Threading.Tasks.Task<TResult>, cada uma possui uma propriedade pública Task<TResult>.Result que contém o resultado do cálculo.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. As tarefas são executadas de forma assíncrona e podem ser concluídas em qualquer ordem.The tasks run asynchronously and may complete in any order. Se a propriedade Result for acessada antes que a computação seja concluída, a propriedade bloqueará o thread de chamada até o valor estar disponível.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

Para obter mais informações, consulte Como retornar um valor de uma tarefa.For more information, see How to: Return a Value from a Task.

Ao usar uma expressão lambda para criar um delegado, você tem acesso a todas as variáveis que são visíveis nesse ponto em seu código-fonte.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. No entanto, em alguns casos, especialmente dentro de loops, um lambda não captura a variável conforme o esperado.However, in some cases, most notably within loops, a lambda doesn't capture the variable as expected. Ele captura somente o valor final, e não o valor no qual ele se transforma após cada iteração.It only captures the final value, not the value as it mutates after each iteration. O exemplo a seguir ilustra o problema.The following example illustrates the problem. Ele passa um contador de loops para uma expressão lambda que instancia um objeto CustomData e usa o contador de loops como o identificador do objeto.It passes a loop counter to a lambda expression that instantiates a CustomData object and uses the loop counter as the object's identifier. Conforme mostra a saída do exemplo, cada objeto CustomData possui um identificador idêntico.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.

Você pode acessar o valor em cada iteração ao fornecer um objeto de estado para uma tarefa através do respectivo construtor.You can access the value on each iteration by providing a state object to a task through its constructor. O exemplo a seguir modifica o exemplo anterior usando o contador de loops ao criar o objeto CustomData, que, em seguida, é transmitido para a expressão 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. Como mostra a saída do exemplo, cada objeto CustomData agora tem um identificador exclusivo com base no valor do contador de loops no momento em que o objeto foi instanciado.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.

Este estado é transmitido como um argumento para o delegado da tarefa e pode ser acessado do objeto de tarefa via propriedade 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. O exemplo a seguir é uma variação do exemplo anterior.The following example is a variation on the previous example. Ele usa a propriedade AsyncState para exibir informações sobre os objetos CustomData passados para a expressão 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 da TarefaTask ID

Cada tarefa recebe um ID inteiro que a identifica exclusivamente em um domínio de aplicativo e que pode ser acessado pela propriedade 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. A ID é útil para exibir informações sobre a tarefa nas janelas Pilhas Paralelas e Tarefas do depurador do Visual Studio.The ID is useful for viewing task information in the Visual Studio debugger Parallel Stacks and Tasks windows. O ID é criado lentamente, o que significa que ele não é criado até que seja solicitado; portanto, uma tarefa pode ter um ID diferente toda vez que o programa é executado.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. Para obter mais informações sobre como exibir IDs de tarefa no depurador, consulte Usando a janela Tarefas e Usando a janela Pilhas Paralelas.For more information about how to view task IDs in the debugger, see Using the Tasks Window and Using the Parallel Stacks Window.

Opções de criação de tarefaTask creation options

A maioria das APIs que criam tarefas fornecem sobrecargas que aceitam um parâmetro TaskCreationOptions.Most APIs that create tasks provide overloads that accept a TaskCreationOptions parameter. Ao especificar uma dessas opções, você informa o agendador de tarefas como agendar a tarefa no pool de threads.By specifying one of these options, you tell the task scheduler how to schedule the task on the thread pool. A tabela a seguir lista as várias opções de criação de tarefas.The following table lists the various task creation options.

Valor do parâmetro TaskCreationOptionsTaskCreationOptions parameter value DescriçãoDescription
None O padrão quando nenhuma opção é especificada.The default when no option is specified. O agendador usa sua heurística padrão para agendar a tarefa.The scheduler uses its default heuristics to schedule the task.
PreferFairness Especifica que a tarefa deve ser agendada de modo que as tarefas criadas antes sejam mais propensas a ser executadas mais cedo, e as tarefas criadas posteriormente sejam mais propensas a ser executadas mais tarde.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 Especifica que a tarefa representa uma operação de execução longa.Specifies that the task represents a long-running operation.
AttachedToParent Especifica que uma tarefa deve ser criada como um filho anexado da tarefa atual, se houver.Specifies that a task should be created as an attached child of the current task, if one exists. Para obter mais informações, consulte Tarefas filho anexadas e desanexadas.For more information, see Attached and Detached Child Tasks.
DenyChildAttach Especifica que, se uma tarefa interna especificar a opção AttachedToParent, ela não se tornará uma tarefa filha anexada.Specifies that if an inner task specifies the AttachedToParent option, that task will not become an attached child task.
HideScheduler Especifica que o agendador de tarefas criadas por meio de chamadas a métodos como TaskFactory.StartNew ou Task<TResult>.ContinueWith de uma tarefa específica é o agendador padrão, e não o agendador no qual essa tarefa está em execução.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.

As opções podem ser combinadas usando uma operação OR bit a bit.The options may be combined by using a bitwise OR operation. O exemplo a seguir mostra uma tarefa que possui as opções 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()

Tarefas, threads e culturaTasks, threads, and culture

Cada thread tem uma cultura associada e uma cultura de interface do usuário, que é definida pelas propriedades Thread.CurrentCulture e Thread.CurrentUICulture, respectivamente.Each thread has an associated culture and UI culture, which is defined by the Thread.CurrentCulture and Thread.CurrentUICulture properties, respectively. A cultura de um thread é usada em operações como formatação, análise, classificação e comparação de cadeia de caracteres.A thread's culture is used in such operations as formatting, parsing, sorting, and string comparison. A cultura de interface do usuário de um thread é usada na pesquisa de recursos.A thread's UI culture is used in resource lookup. Em geral, a menos que você especifique uma cultura padrão para todos os threads em um domínio de aplicativo usando as propriedades CultureInfo.DefaultThreadCurrentCulture e CultureInfo.DefaultThreadCurrentUICulture, a cultura padrão e a cultura de interface do usuário de um thread são definidas pela cultura do 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 você definir a cultura de um thread de forma explícita e iniciar um novo thread, o novo thread não herdará a cultura do thread de chamada; em vez disso, sua cultura será a cultura padrão do 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. O modelo de programação baseado em tarefas para aplicativos destinados a versões do .NET Framework anteriores ao .NET Framework 4.6 segue essa prática.The task-based programming model for apps that target versions of the .NET Framework prior to .NET Framework 4.6 adhere to this practice.

Importante

Observe que a cultura do thread de chamada como parte do contexto de uma tarefa se aplica aos aplicativos destinados ao .NET Framework 4.6, não aos aplicativos executados no .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, not apps that run under the .NET Framework 4.6. Você pode definir como destino uma versão específica do .NET Framework ao criar seu projeto no Visual Studio selecionando essa versão na lista suspensa na parte superior da caixa de diálogo Novo Projeto, ou fora do Visual Studio, você pode usar o atributo 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. Para aplicativos destinados a versões do .NET Framework anteriores ao .NET Framework 4.6 ou que não são destinados a uma versão específica do .NET Framework, a cultura de uma tarefa continua sendo determinada pela cultura do thread no qual ela é executada.For apps that target versions of the .NET Framework prior to the .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.

Começando com aplicativos destinados ao .NET Framework 4.6, a cultura do thread de chamada será herdada por cada tarefa, mesmo se a tarefa for executada de forma assíncrona em um pool de threads.Starting with apps that target the .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.

O exemplo a seguir fornece uma ilustração simples.The following example provides a simple illustration. Ele usa o atributo TargetFrameworkAttribute para definir o .NET Framework 4.6 como destino e altera a cultura atual do aplicativo para o francês (França) ou, caso o francês (França) já seja a cultura atual, para o inglês (Estados Unidos).It uses the TargetFrameworkAttribute attribute to target the .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). Depois, ele chama um delegado chamado formatDelegate que retorna alguns números formatados como valores de moeda na nova cultura.It then invokes a delegate named formatDelegate that returns some numbers formatted as currency values in the new culture. Observe que, se o delegado como uma tarefa de forma síncrona ou assíncrona, ele retorna o resultado esperado, pois a cultura do thread de chamada é herdada pela tarefa assíncrona.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 você estiver usando o Visual Studio, poderá omitir o atributo TargetFrameworkAttribute e selecionar o .NET Framework 4.6 como destino ao criar o projeto na caixa de diálogo Novo Projeto.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.

Para obter um resultado que reflete o comportamento de aplicativos destinados a versões do .NET Framework anteriores ao .NET Framework 4.6, remova o atributo TargetFrameworkAttribute do código-fonte.For output that reflects the behavior of apps the target versions of the .NET Framework prior to .NET Framework 4.6, remove the TargetFrameworkAttribute attribute from the source code. O resultado refletirá as convenções de formatação da cultura padrão do sistema, não da cultura do thread de chamada.The output will reflect the formatting conventions of the default system culture, not the culture of the calling thread.

Para saber mais sobre a cultura e tarefas assíncronas, veja a seção “Cultura e operações assíncronas baseadas em tarefas assíncronas” no tópico CultureInfo.For more information on asynchronous tasks and culture, see the "Culture and asynchronous task-based operations" section in the CultureInfo topic.

Criando continuações de tarefaCreating task continuations

Os métodos Task.ContinueWith e Task<TResult>.ContinueWith permitem que você especifique uma tarefa para iniciar quando a tarefa antecedente terminar.The Task.ContinueWith and Task<TResult>.ContinueWith methods let you specify a task to start when the antecedent task finishes. O delegado da tarefa de continuação recebe uma referência à tarefa antecedente para que possa examinar o status da tarefa antecedente e, ao recuperar o valor da propriedade Task<TResult>.Result, pode usar a saída do antecedente como entrada para a continuação.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.

No exemplo a seguir, a tarefa getData é iniciada por uma chamada feita ao método 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. A tarefa processData é iniciada automaticamente quando getData termina, e displayData é iniciada quando processData termina.The processData task is started automatically when getData finishes, and displayData is started when processData finishes. getData produz uma matriz de inteiros que é acessível para a tarefa processData por meio da propriedade getData da tarefa Task<TResult>.Result.getData produces an integer array, which is accessible to the processData task through the getData task's Task<TResult>.Result property. A tarefa processData processa a matriz e retorna um resultado cujo tipo é derivado do tipo retornado pela expressão lambda passada ao método 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. A tarefa displayData é executada automaticamente quando processData é concluído e o objeto Tuple<T1,T2,T3> retornado pela expressão lambda processData é acessível para a tarefa de displayData através da propriedade processData da tarefa 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. A tarefa displayData recebe o resultado da tarefa processData e gera um resultado cujo tipo é inferido de maneira semelhante e que é disponibilizado para o programa na propriedade 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

Como Task.ContinueWith é um método de instância, é possível encadear as chamadas de método juntas em vez de criar uma instância de um objeto de Task<TResult> para cada tarefa antecedente.Because Task.ContinueWith is an instance method, you can chain method calls together instead of instantiating a Task<TResult> object for each antecedent task. O exemplo a seguir é funcionalmente idêntico ao exemplo anterior, exceto que ele encadeia chamadas ao método Task.ContinueWith.The following example is functionally identical to the previous example, except that it chains together calls to the Task.ContinueWith method. Observe que o objeto de Task<TResult> retornado pela cadeia de chamadas de métodos é a tarefa final de continuação.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

Os métodos ContinueWhenAll e ContinueWhenAny permitem que você continue de várias tarefas.The ContinueWhenAll and ContinueWhenAny methods enable you to continue from multiple tasks.

Para obter mais informações, consulte Encadeando tarefas com tarefas de continuação.For more information, see Chaining Tasks by Using Continuation Tasks.

Criando tarefas filho desanexadasCreating detached child tasks

Quando o código do usuário que está executando em uma tarefa cria uma nova tarefa e não especifica a opção de AttachedToParent, a nova tarefa não é sincronizada com a tarefa pai de nenhuma forma especial.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. Esse tipo de tarefa não sincronizada é chamada de tarefa aninhada desanexada ou tarefa filho desanexada.This type of non-synchronized task is called a detached nested task or detached child task. O exemplo a seguir mostra uma tarefa que cria uma tarefa filha desanexada.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.

Observe que a tarefa pai não espera a tarefa filha desanexada terminar.Note that the parent task does not wait for the detached child task to finish.

Criando tarefas filhoCreating child tasks

Quando o código do usuário que está executando em uma tarefa cria uma tarefa com a opção AttachedToParent, a nova tarefa é conhecida como uma tarefa filha anexada da tarefa pai.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. Você pode usar a opção AttachedToParent para expressar o paralelismo estruturado das tarefas, porque a tarefa pai espera implicitamente todas as tarefas filhas anexadas terminarem.You can use the AttachedToParent option to express structured task parallelism, because the parent task implicitly waits for all attached child tasks to finish. O exemplo a seguir mostra uma tarefa pai que cria dez tarefas filhas anexadas.The following example shows a parent task that creates ten attached child tasks. Observe que, embora o exemplo chame o método Task.Wait para aguardar que a tarefa pai seja concluída, ele não precisará aguardar explicitamente que as tarefas filhas anexadas sejam concluídas.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.

Uma tarefa pai pode usar a opção TaskCreationOptions.DenyChildAttach para impedir que outras tarefas se anexem à tarefa pai.A parent task can use the TaskCreationOptions.DenyChildAttach option to prevent other tasks from attaching to the parent task. Para obter mais informações, consulte Tarefas filho anexadas e desanexadas.For more information, see Attached and Detached Child Tasks.

Aguardando a conclusão das tarefasWaiting for tasks to finish

Os tipos System.Threading.Tasks.Task e System.Threading.Tasks.Task<TResult> fornecem várias sobrecargas dos métodos Task.Wait que permitem aguardar a conclusão de uma tarefa.The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> types provide several overloads of the Task.Wait methods that enable you to wait for a task to finish. Além disso, as sobrecargas dos métodos estáticos Task.WaitAll e Task.WaitAny permitem que você aguarde a conclusão de qualquer uma ou de todas as matrizes de tarefas.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.

Normalmente, você esperaria uma tarefa por um destes motivos:Typically, you would wait for a task for one of these reasons:

  • O thread principal depende do resultado final calculado por uma tarefa.The main thread depends on the final result computed by a task.

  • Você precisa tratar exceções que podem ser geradas pela tarefa.You have to handle exceptions that might be thrown from the task.

  • O aplicativo pode terminar antes que todas as tarefas concluam a execução.The application may terminate before all tasks have completed execution. Por exemplo, aplicativos de console terminarão assim que todos os códigos síncronos em Main (o ponto de entrada do aplicativo) tiverem sido executados.For example, console applications will terminate as soon as all synchronous code in Main (the application entry point) has executed.

O exemplo a seguir mostra o padrão básico que não envolve tratamento de exceções.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...

Para obter um exemplo que mostra o tratamento de exceções, consulte Tratamento de exceções.For an example that shows exception handling, see Exception Handling.

Algumas sobrecargas permitem especificar um tempo limite, e outras usam um CancellationToken adicional como um parâmetro de entrada para que a espera possa ser cancelada programaticamente ou em resposta a uma entrada do usuário.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.

Ao aguardar uma tarefa, você espera implicitamente todas as filhos da tarefa que foram criadas usando a opção 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. Task.Wait retorna imediatamente se a tarefa já foi concluída.Task.Wait returns immediately if the task has already completed. Todas as exceções geradas por uma tarefa serão geradas por um método Task.Wait, mesmo se o método Task.Wait tiver sido chamado após o término da tarefa.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.

Compondo tarefasComposing tasks

As classes Task e Task<TResult> fornecem vários métodos que podem ajudá-lo na composição de várias tarefas para implementar padrões comuns e melhorar o uso dos recursos de linguagem assíncronos que são fornecidos por 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#. Esta seção descreve os métodos WhenAll, WhenAny, Delay e FromResult.This section describes the WhenAll, WhenAny, Delay, and FromResult methods.

Task.WhenAllTask.WhenAll

O método Task.WhenAll espera assincronamente a conclusão de vários objetos Task ou Task<TResult>.The Task.WhenAll method asynchronously waits for multiple Task or Task<TResult> objects to finish. Ele fornece versões sobrecarregadas que permitem aguardar conjuntos não uniformes de tarefas.It provides overloaded versions that enable you to wait for non-uniform sets of tasks. Por exemplo, você pode aguardar vários objetos Task e Task<TResult> para concluir após uma chamada de método.For example, you can wait for multiple Task and Task<TResult> objects to complete from one method call.

Task.WhenAnyTask.WhenAny

O método Task.WhenAny espera assincronamente a conclusão de um de vários objetos Task ou Task<TResult>.The Task.WhenAny method asynchronously waits for one of multiple Task or Task<TResult> objects to finish. Assim como no método Task.WhenAll, esse método oferece as versões sobrecarregadas que permitem aguardar conjuntos não uniformes de tarefas.As in the Task.WhenAll method, this method provides overloaded versions that enable you to wait for non-uniform sets of tasks. O método WhenAny é especialmente útil nos cenários a seguir.The WhenAny method is especially useful in the following scenarios.

  • Operações redundantes.Redundant operations. Considere um algoritmo ou uma operação que possam ser executados de várias maneiras.Consider an algorithm or operation that can be performed in many ways. Você pode usar o método WhenAny para selecionar a operação que termina primeiro e então cancelar as operações restantes.You can use the WhenAny method to select the operation that finishes first and then cancel the remaining operations.

  • Operações intercaladas.Interleaved operations. Você pode iniciar várias operações que todos devem concluir e usar o método WhenAny para processar resultados à medida que cada operação termina.You can start multiple operations that must all finish and use the WhenAny method to process results as each operation finishes. Após uma operação ser concluída, você poderá começar uma ou mais tarefas adicionais.After one operation finishes, you can start one or more additional tasks.

  • Operações controladas.Throttled operations. Você pode usar o método WhenAny para estender o cenário anterior ao limitar o número de operações simultâneas.You can use the WhenAny method to extend the previous scenario by limiting the number of concurrent operations.

  • Operações expiradas.Expired operations. Você pode usar o método WhenAny para selecionar entre uma ou mais tarefas e uma tarefa que termine após uma hora específica, como uma tarefa que é retornada pelo método 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. O método Delay é descrito na seção a seguir.The Delay method is described in the following section.

Task.DelayTask.Delay

O método Task.Delay gera um objeto Task que se encerra após o tempo especificado.The Task.Delay method produces a Task object that finishes after the specified time. Você pode usar esse método para compilar os loop que, ocasionalmente, procuram dados, introduzem tempos limites, atrasam manipulação de entrada do usuário por um período pré-determinado e assim por diante.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

Ao usar o método Task.FromResult, você pode criar um objeto Task<TResult> com um resultado pré-calculado.By using the Task.FromResult method, you can create a Task<TResult> object that holds a pre-computed result. Este método é útil quando você executa uma operação assíncrona que retorna um objeto Task<TResult> e o resultado do objeto Task<TResult> já está calculado.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. Para obter um exemplo que use FromResult para recuperar os resultados de operações de download assíncronas mantidas em um cache, veja Como criar tarefas pré-computadas.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.

Tratando exceções em tarefasHandling exceptions in tasks

Quando uma tarefa gera uma ou mais exceções, as exceções são envolvidas em uma exceção AggregateException.When a task throws one or more exceptions, the exceptions are wrapped in an AggregateException exception. Essa exceção é propagada de volta para o thread que se associa à tarefa, que normalmente é o thread que está aguardando a conclusão da tarefa ou o thread que acessa a propriedade 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. Esse comportamento serve para impor a política do .NET Framework de que todas as exceções sem tratamento devem, por padrão, encerrar o processo.This behavior serves to enforce the .NET Framework policy that all unhandled exceptions by default should terminate the process. O código de chamada pode tratar as exceções usando uma destas opções em um bloco try/catch:The calling code can handle the exceptions by using any of the following in a try/catch block:

O thread de associação também pode manipular exceções ao acessar a propriedade Exception antes que a tarefa seja coletada pela lixeira.The joining thread can also handle exceptions by accessing the Exception property before the task is garbage-collected. Ao acessar essa propriedade, você impede que a exceção sem tratamento dispare o comportamento de propagação de exceção que finaliza o processo quando o objeto é encerrado.By accessing this property, you prevent the unhandled exception from triggering the exception propagation behavior that terminates the process when the object is finalized.

Para obter mais informações sobre exceções e tarefas, consulte Tratamento de exceções.For more information about exceptions and tasks, see Exception Handling.

Cancelando tarefasCanceling tasks

A classe Task oferece suporte ao cancelamento cooperativo e é totalmente integrada às classes System.Threading.CancellationTokenSource e System.Threading.CancellationToken, as quais foram introduzidas no .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. Muitos dos construtores na classe System.Threading.Tasks.Task recebem um objeto CancellationToken como um parâmetro de entrada.Many of the constructors in the System.Threading.Tasks.Task class take a CancellationToken object as an input parameter. Várias das sobrecargas StartNew e Run também incluem um parâmetro CancellationToken.Many of the StartNew and Run overloads also include a CancellationToken parameter.

Você pode criar o token e enviar a solicitação de cancelamento algum tempo depois usando a classe CancellationTokenSource.You can create the token, and issue the cancellation request at some later time, by using the CancellationTokenSource class. Passe o token para Task como um argumento e também referencie o mesmo token em seu delegado de usuário, o qual faz o trabalho de responder a uma solicitação de cancelamento.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.

Para obter mais informações, consulte Cancelamento de tarefas e Como cancelar uma tarefa e seus filhos.For more information, see Task Cancellation and How to: Cancel a Task and Its Children.

A classe TaskFactoryThe TaskFactory class

A classe TaskFactory fornece métodos estáticos que encapsulam alguns padrões comuns para criar e iniciar tarefas e tarefas de continuação de linha.The TaskFactory class provides static methods that encapsulate some common patterns for creating and starting tasks and continuation tasks.

O TaskFactory padrão pode ser acessado como uma propriedade estática na classe Task ou na classe Task<TResult>.The default TaskFactory can be accessed as a static property on the Task class or Task<TResult> class. Você também pode criar uma instância TaskFactory diretamente e especificar várias opções que incluem CancellationToken, uma opção TaskCreationOptions, uma opção TaskContinuationOptions ou um 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. As opções especificadas quando você cria a fábrica de tarefas serão aplicadas a todas as tarefas criadas por ela, a menos que Task seja criada usando a enumeração TaskCreationOptions. Nesse caso, as opções de tarefa substituem as da fábrica de tarefas.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.

Tarefas sem representantesTasks without delegates

Em alguns casos, convém usar Task para encapsular qualquer operação assíncrona executada por um componente externo em vez de seu próprio delegado de usuário.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 a operação for baseada no padrão Begin/End do modelo de programação assíncrona, você poderá usar os métodos FromAsync.If the operation is based on the Asynchronous Programming Model Begin/End pattern, you can use the FromAsync methods. Se esse não for o caso, você poderá usar o objeto TaskCompletionSource<TResult> para envolver a operação em uma tarefa e obter assim alguns benefícios de programabilidade Task, por exemplo, suporte a propagação e continuações de exceção.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. Para obter mais informações, consulte TaskCompletionSource<TResult>.For more information, see TaskCompletionSource<TResult>.

Agendadores personalizadosCustom schedulers

A maioria dos desenvolvedores de aplicativos ou bibliotecas não se importa com o processador em que a tarefa é executada, como ele sincroniza seu trabalho com outras tarefas e como ela é agendada em 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. Eles apenas exigem que ela seja executada da maneira mais eficiente possível no computador host.They only require that it execute as efficiently as possible on the host computer. Se você exigir um controle mais aguçado sobre os detalhes de programação, a Biblioteca Paralela de Tarefas permite definir algumas configurações no agendador de tarefas padrão e permite até mesmo fornecer um agendador personalizado.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. Para obter mais informações, consulte TaskScheduler.For more information, see TaskScheduler.

A TPL possui vários novos tipos públicos que são úteis em cenários paralelos e sequenciais.The TPL has several new public types that are useful in both parallel and sequential scenarios. Esses incluem várias classes de coleção thread-safe, rápida e dimensionável no namespace System.Collections.Concurrent, e vários novos tipos de sincronização, por exemplo, System.Threading.Semaphore e System.Threading.ManualResetEventSlim, que são mais eficientes do que seus antecessores para tipos específicos de cargas de trabalho.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. Outros novos tipos no .NET Framework 4, por exemplo, System.Threading.Barrier e System.Threading.SpinLock, fornecem a funcionalidade que não estava disponível em versões anteriores.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. Para obter mais informações, consulte Estruturas de dados para programação paralela.For more information, see Data Structures for Parallel Programming.

Tipos de tarefa personalizadosCustom task types

Recomendamos que você não herde de System.Threading.Tasks.Task ou de System.Threading.Tasks.Task<TResult>.We recommend that you do not inherit from System.Threading.Tasks.Task or System.Threading.Tasks.Task<TResult>. Em vez disso, recomenda-se usar a propriedade AsyncState para associar dados adicionais ou o estado a um objeto Task ou Task<TResult>.Instead, we recommend that you use the AsyncState property to associate additional data or state with a Task or Task<TResult> object. Você também pode usar os métodos de extensão para estender a funcionalidade de Task e Task<TResult>.You can also use extension methods to extend the functionality of the Task and Task<TResult> classes. Para obter mais informações sobre métodos de extensão, consulte Métodos de extensão e Métodos de extensão.For more information about extension methods, see Extension Methods and Extension Methods.

Se for necessário herdar de Task ou Task<TResult>, você não poderá usar Run, Run ou System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>, ou as classes System.Threading.Tasks.TaskCompletionSource<TResult> para criar instâncias de seu tipo de tarefa personalizada, pois esses mecanismos criam somente objetos 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. Além disso, você não pode usar os mecanismos de continuação de tarefas fornecidos por Task, Task<TResult>, TaskFactory e TaskFactory<TResult> para criar instâncias de seu tipo de tarefa personalizada porque esses mecanismos também criam apenas objetos 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.

TítuloTitle DescriçãoDescription
Encadeando tarefas usando tarefas de continuaçãoChaining Tasks by Using Continuation Tasks Descreve como as continuações funcionam.Describes how continuations work.
Tarefas filho anexadas e desanexadasAttached and Detached Child Tasks Descreve a diferença entre tarefas filhas anexadas e desanexadas.Describes the difference between attached and detached child tasks.
Cancelamento de tarefasTask Cancellation Descreve o suporte a cancelamento interno do objeto Task.Describes the cancellation support that is built into the Task object.
Tratamento de ExceçãoException Handling Descreve como as exceções são manipuladas em threads simultâneos.Describes how exceptions on concurrent threads are handled.
Como usar Parallel.Invoke para executar operações em paraleloHow to: Use Parallel.Invoke to Execute Parallel Operations Descreve como usar o Invoke.Describes how to use Invoke.
Como retornar um valor de uma tarefaHow to: Return a Value from a Task Descreve como retornar valores de tarefas.Describes how to return values from tasks.
Como cancelar uma tarefa e seus filhosHow to: Cancel a Task and Its Children Descreve como cancelar tarefas.Describes how to cancel tasks.
Como criar tarefas pré-computadasHow to: Create Pre-Computed Tasks Descreve como usar o método Task.FromResult para recuperar os resultados das operações de download assíncronas armazenados em um cache.Describes how to use the Task.FromResult method to retrieve the results of asynchronous download operations that are held in a cache.
Como percorrer uma árvore binária com tarefas paralelasHow to: Traverse a Binary Tree with Parallel Tasks Descreve como usar tarefas para percorrer uma árvore binária.Describes how to use tasks to traverse a binary tree.
Como desencapsular uma tarefa aninhadaHow to: Unwrap a Nested Task Demonstra como usar o método de extensão Unwrap.Demonstrates how to use the Unwrap extension method.
Paralelismo de dadosData Parallelism Descreve como usar For e ForEach para criar loops paralelos sobre dados.Describes how to use For and ForEach to create parallel loops over data.
Programação paralelaParallel Programming Nó de nível superior para a programação paralela do .NET Framework.Top level node for .NET Framework parallel programming.

Consulte tambémSee also