Aninhados de tarefas e tarefas filho
Uma tarefa aninhada é apenas um Task instância é criada no delegado usuário de outra tarefa. A tarefa filho é uma tarefa de aninhado é criada com o AttachedToParent opção. Uma tarefa pode criar qualquer número de filhos e/ou tarefas aninhadas, limitadas apenas pelos recursos do sistema. O exemplo a seguir mostra uma tarefa pai que cria uma tarefa simple de aninhados.
Shared Sub SimpleNestedTask()
Dim parent = Task.Factory.StartNew(Sub()
Console.WriteLine("Outer task executing.")
Dim child = Task.Factory.StartNew(Sub()
Console.WriteLine("Nested task starting.")
Thread.SpinWait(500000)
Console.WriteLine("Nested task completing.")
End Sub)
End Sub)
parent.Wait()
Console.WriteLine("Outer task has completed.")
End Sub
' Sample output:
' Outer task executing.
' Nested task starting.
' Outer task has completed.
' Nested task completing.
static void SimpleNestedTask()
{
var parent = Task.Factory.StartNew(() =>
{
Console.WriteLine("Outer task executing.");
var child = Task.Factory.StartNew(() =>
{
Console.WriteLine("Nested task starting.");
Thread.SpinWait(500000);
Console.WriteLine("Nested task completing.");
});
});
parent.Wait();
Console.WriteLine("Outer has completed.");
}
/* Sample output:
Outer task executing.
Nested task starting.
Outer has completed.
Nested task completing.
*/
Tarefas de filho anexado Versus desanexadas tarefas aninhadas
O ponto mais importante em relação ao filho vs. tarefas aninhadas é que tarefas aninhadas basicamente independentes do pai ou tarefa externa, enquanto associados ao filho tarefas muito estreitamente sincronizadas com o pai. Se você alterar a instrução de criação de tarefa para usar o AttachedToParent opção, conforme mostrado no exemplo a seguir
Dim child = Task.Factory.StartNew(Sub()
Console.WriteLine("Attached child starting.")
Thread.SpinWait(5000000)
Console.WriteLine("Attached child completing.")
End Sub, TaskCreationOptions.AttachedToParent)
var child = Task.Factory.StartNew((t) =>
{
Console.WriteLine("Attached child starting.");
Thread.SpinWait(5000000);
Console.WriteLine("Attached child completing.");
}, TaskCreationOptions.AttachedToParent);
a seguinte saída poderia ser produzida.
' Parent task executing.
' Attached child starting.
' Attached child completing.
' Parent has completed.
Parent task executing.
Attached child starting.
Attached child completing.
Parent has completed.
Você pode usar tarefas filho anexado para criar gráficos de totalmente sincronizada de operações assíncronas. No entanto, na maioria dos cenários, recomendamos que você use aninhadas tarefas porque as relações com outras tarefas são menos complexas. Isto é porque as tarefas criadas dentro de outras tarefas estão aninhadas por padrão e você deve especificar explicitamente o AttachedToParent opção para criar uma tarefa filho.
A tabela a seguir lista as diferenças básicas entre os dois tipos de tarefas filho.
<strong>Categoria</strong> |
Tarefas aninhadas |
Tarefas de filho anexado |
---|---|---|
Tarefa externa (pai) aguarda para tarefas internas concluir. |
Não |
Sim |
Pai propaga exceções lançadas por crianças (tarefas internas). |
Não |
Sim |
Status do pai (tarefa externa) depende do status do filho (tarefa interna). |
Não |
Sim |
Desanexado cenários onde a tarefa aninhada é um Task<TResult>, você ainda pode forçar o pai para aguardar uma criança, acessando o Result a propriedade da tarefa aninhados. O Result propriedade bloqueia até que a tarefa seja concluída.
Shared Sub WaitForSimpleNestedTask()
Dim parent = Task(Of Integer).Factory.StartNew(Function()
Console.WriteLine("Outer task executing.")
Dim child = Task(Of Integer).Factory.StartNew(Function()
Console.WriteLine("Nested task starting.")
Thread.SpinWait(5000000)
Console.WriteLine("Nested task completing.")
Return 42
End Function)
Return child.Result
End Function)
Console.WriteLine("Outer has returned {0}", parent.Result)
End Sub
'Sample output:
' Outer task executing.
' Nested task starting.
' Detached task completing.
' Outer has returned 42
static void WaitForSimpleNestedTask()
{
var outer = Task<int>.Factory.StartNew(() =>
{
Console.WriteLine("Outer task executing.");
var nested = Task<int>.Factory.StartNew(() =>
{
Console.WriteLine("Nested task starting.");
Thread.SpinWait(5000000);
Console.WriteLine("Nested task completing.");
return 42;
});
// Parent will wait for this detached child.
return nested.Result;
});
Console.WriteLine("Outer has returned {0}.", outer.Result);
}
/* Sample output:
Outer task executing.
Nested task starting.
Nested task completing.
Outer has returned 42.
*/
Exceções aninhadas e tarefas filho
Se uma tarefa aninhada lança uma exceção, ele deve ser observado ou manipulado diretamente na tarefa externa, como ocorre com qualquer tarefa não aninhados. Se uma criança anexada lança uma exceção, a exceção é automaticamente propagada para a tarefa de pai e volta para o segmento que espera ou tenta acessar a tarefa Result propriedade. Portanto, usando tarefas filho anexado, você pode manipular todas as exceções em apenas um ponto, isto é, a chamada para aguardar no thread de chamada. Para obter mais informações, consulte (Biblioteca paralela de tarefas) de manipulação de exceção.
Cancelamento e tarefas filho
Lembre-se de que o cancelamento da tarefa é cooperativo. Portanto, para ser "cancelável" cada tarefa anexado ou desanexado filho deve monitorar o status do token de cancelamento. Se desejar cancelar um pai e todos os seus filhos por meio de uma solicitação de cancelamento, passe o mesmo token, como um argumento para todas as tarefas e a fornecer a lógica para responder à solicitação de cada tarefa. Para obter mais informações, consulte Cancelamento da tarefa e Como: Cancelar uma tarefa e seus filhos.
Quando o pai cancela
Se um pai se auto cancela antes do início de uma criança, a tarefa de filho (aninhada) obviamente nunca será iniciado. Se um pai cancela a mesmo após um filho ou aninhada tarefa já foi iniciada, a tarefa de aninhados (filho) será executada até a conclusão, a menos que ele tem sua própria lógica de cancelamento. Para obter mais informações, consulte Cancelamento da tarefa.
Quando cancela a uma tarefa aninhada
Se uma tarefa filho desanexado cancela a mesmo usando o mesmo token que foi passado para a tarefa e não espera o pai no filho, nenhuma exceção é propagada como a exceção é tratada como o cancelamento de cooperação benigno. Esse comportamento é a mesma de qualquer tarefa de nível superior.
Quando cancela a uma tarefa filho
Quando se auto cancela uma tarefa filho anexado usando o mesmo token que foi passado para a tarefa, um TaskCanceledException é propagada para o segmento de ingresso dentro de um AggregateException. É muito importante aguardar a tarefa pai para que você pode manipular todas as exceções benignas, além de para todas as exceções com falha propagadas por meio de um gráfico das tarefas filho anexado.
Para obter mais informações, consulte (Biblioteca paralela de tarefas) de manipulação de exceção.