No momento, estou lendo " Concurrency in C # Cookbook ", de Stephen Cleary, e percebi a seguinte técnica:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask
é uma chamada para httpclient.GetStringAsync
e timeoutTask
está em execução Task.Delay
.
Caso não tenha expirado, então downloadTask
já está concluído. Por que é necessário fazer uma segunda espera em vez de retornar downloadTask.Result
, visto que a tarefa já está concluída?
c#
asynchronous
async-await
task
julio.g
fonte
fonte
downloadTask
etimeoutTask
? O que eles fazem?AggregateException
comResult
vs primeira exceção viaExceptionDispatchInfo
comawait
). Discutido com mais detalhes em "Manipulação de exceções de tarefas no .NET 4.5" de Stephen Toub: blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )Respostas:
Já existem algumas boas respostas / comentários aqui, mas apenas para interromper ...
Há duas razões pelas quais eu prefiro
await
maisResult
(ouWait
). A primeira é que o tratamento de erros é diferente;await
não envolve a exceção em umAggregateException
. Idealmente, o código assíncrono nunca deveria ter que lidarAggregateException
, a menos que especificamente queira .A segunda razão é um pouco mais sutil. Conforme descrevo em meu blog (e no livro),
Result
/Wait
pode causar deadlocks e pode causar ainda mais deadlocks sutis quando usado em umasync
método . Portanto, quando estou lendo o código e vejo umResult
ouWait
, é um sinalizador de aviso imediato. OResult
/Wait
só está correto se você tiver certeza absoluta de que a tarefa já foi concluída. Não é apenas difícil de ver à primeira vista (no código do mundo real), mas também é mais frágil para alterações de código.Isso não quer dizer que
Result
/ nuncaWait
deva ser usado. Eu sigo essas diretrizes em meu próprio código:await
.Result
/Wait
se o código realmente exigir. Esse uso provavelmente deve ter comentários.Result
eWait
.Observe que (1) é de longe o caso comum, daí minha tendência de usar em
await
todos os lugares e tratar os outros casos como exceções à regra geral.fonte
await
impede oAggregateException
invólucro.AggregateException
foi projetado para programação paralela, não para programação assíncrona.Wait
era juntar a instâncias de Paralelismo de Tarefa DinâmicaTask
. Usá-lo para esperar porTask
instâncias assíncronas é perigoso. A Microsoft considerou a introdução de um novo tipo de "Promessa", mas optou por usar o existenteTask
; a desvantagem de reutilizar oTask
tipo existente para tarefas assíncronas é que você acaba com várias APIs que simplesmente não deveriam ser usadas em código assíncrono.Isso faz sentido se
timeoutTask
for um produto doTask.Delay
qual acredito no que está no livro.Task.WhenAny
retornaTask<Task>
, onde a tarefa interna é uma daquelas que você passou como argumentos. Ele poderia ser reescrito assim:Em ambos os casos, porque
downloadTask
já foi concluído, há uma diferença muito pequena entrereturn await downloadTask
ereturn downloadTask.Result
. É que o último irá lançar oAggregateException
que envolve qualquer exceção original, como apontado por @KirillShlenskiy nos comentários. O primeiro iria apenas relançar a exceção original.Em qualquer um dos casos, sempre que você lida com exceções, deve verificar
AggregateException
suas exceções internas de qualquer maneira, para chegar à causa do erro.fonte