Disseram-me recentemente que a forma como eu estava usando meu .ContinueWith for Tasks não era a maneira correta de usá-los. Ainda não encontrei evidências disso na internet, então vou perguntar a vocês e ver qual é a resposta. Aqui está um exemplo de como eu uso .ContinueWith:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}
Agora eu sei que este é um exemplo simples e será executado muito rápido, mas apenas suponha que cada tarefa execute uma operação mais longa. Então, o que me disseram é que no .ContinueWith, você precisa dizer prevTask.Wait (); caso contrário, você pode trabalhar antes que a tarefa anterior termine. É mesmo possível? Presumi que minha segunda e terceira tarefas só seriam executadas quando a tarefa anterior terminasse.
O que me disseram como escrever o código:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 3");
});
}
c#
task-parallel-library
Travyguy9
fonte
fonte
Respostas:
Ehhh .... Acho que algumas das respostas atuais estão faltando alguma coisa: o que acontece com as exceções?
A única razão pela qual você chamaria
Wait
uma continuação seria observar uma exceção potencial do antecedente na própria continuação. A mesma observação aconteceria se você acessasseResult
no caso de aTask<T>
e também se acessasse manualmente aException
propriedade. Francamente, eu não chamariaWait
ou acessariaResult
porque, se houver uma exceção, você pagará o preço de aumentá-la novamente, o que é um overhead desnecessário. Em vez disso, você pode apenas verificar aIsFaulted
propriedade do antecedenteTask
. Alternativamente, você pode criar fluxos de trabalho bifurcados encadeando em várias continuações de irmãos que só disparam com base no sucesso ou falha comTaskContinuationOptions.OnlyOnRanToCompletion
eTaskContinuationOptions.OnlyOnFaulted
.Agora, não é necessário observar a exceção do antecedente na continuação, mas você pode não querer que seu fluxo de trabalho avance se, digamos, "Etapa 1" falhou. Nesse caso: a especificação
TaskContinuationOptions.NotOnFaulted
de suasContinueWith
chamadas evitaria que a lógica de continuação até mesmo fosse acionada.Lembre-se de que, se suas próprias continuações não observarem a exceção, a pessoa que está aguardando a conclusão desse fluxo de trabalho geral será aquela que observará. Ou eles estão
Wait
subindo oTask
rio ou aderiram à sua própria continuação para saber quando ela está completa. Se for o último, sua continuação precisaria usar a lógica de observação mencionada.fonte
TaskContinuationOptions
Você está usando corretamente.
Fonte: método Task.ContinueWith (ação como MSDN)
Ter que chamar
prevTask.Wait()
todas asTask.ContinueWith
invocações parece uma maneira estranha de repetir a lógica desnecessária - isto é, fazer algo para ter "certeza absoluta" porque você na verdade não entende o que um determinado código faz. Como verificar se há um nulo apenas para lançar umArgumentNullException
onde teria sido lançado de qualquer maneira.Então, não, quem te disse isso está errado e provavelmente não entende porque
Task.ContinueWith
existe.fonte
Quem te disse isso?
Citando MSDN :
Além disso, qual seria o propósito de Continue With se não estivesse esperando a conclusão da tarefa anterior?
Você pode até mesmo testá-lo:
fonte
Do MSDN em diante
Task.Continuewith
Eu acho que a maneira que você espera que funcione no primeiro exemplo é a maneira correta.
fonte
Você também pode querer considerar o uso de Task.Run em vez de Task.Factory.StartNew.
A postagem no blog de Stephen Cleary e a postagem de Stephen Toub às quais ele faz referência explicam as diferenças. Há também uma discussão nesta resposta .
fonte
Ao acessar,
Task.Result
você está fazendo uma lógica semelhante atask.wait
fonte
Vou reiterar o que muitos já falaram,
prevTask.Wait()
é desnecessário .Para mais exemplos, pode-se ir para Chaining Tasks usando Continuation Tasks , outro link da Microsoft com bons exemplos.
fonte