Je lis actuellement " Concurrency in C # Cookbook " de Stephen Cleary, et j'ai remarqué la technique suivante:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask
est un appel à httpclient.GetStringAsync
, et timeoutTask
est en cours d'exécution Task.Delay
.
Dans le cas où il n'a pas expiré, alors downloadTask
est déjà terminé. Pourquoi est-il nécessaire de faire une seconde attente au lieu de revenir downloadTask.Result
, étant donné que la tâche est déjà terminée?
c#
asynchronous
async-await
task
julio.g
la source
la source
downloadTask
ettimeoutTask
? Que font-ils?AggregateException
avecResult
vs première exception viaExceptionDispatchInfo
avecawait
). Discuté plus en détail dans "Task Exception Handling in .NET 4.5" de Stephen Toub: blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )Réponses:
Il y a déjà de bonnes réponses / commentaires ici, mais juste pour intervenir ...
Il y a deux raisons pour lesquelles je préfère
await
surResult
(ouWait
). Le premier est que la gestion des erreurs est différente;await
n'enveloppe pas l'exception dans un fichierAggregateException
. Idéalement, le code asynchrone ne devrait jamais avoir à gérerAggregateException
du tout, à moins qu'il ne veuille spécifiquement .La deuxième raison est un peu plus subtile. Comme je le décris sur mon blog (et dans le livre),
Result
/Wait
peut provoquer des blocages , et peut provoquer des blocages encore plus subtils lorsqu'il est utilisé dans uneasync
méthode . Ainsi, lorsque je lis du code et que je vois unResult
ouWait
, c'est un indicateur d'avertissement immédiat. LeResult
/Wait
n'est correct que si vous êtes absolument sûr que la tâche est déjà terminée. Non seulement c'est difficile à voir en un coup d'œil (dans le code du monde réel), mais c'est aussi plus fragile aux changements de code.Cela ne veut pas dire que
Result
/ neWait
devrait jamais être utilisé. Je suis ces directives dans mon propre code:await
.Result
/Wait
si le code l'exige vraiment. Un tel usage devrait probablement avoir des commentaires.Result
etWait
.Notez que (1) est de loin le cas courant, d'où ma tendance à utiliser
await
partout et à traiter les autres cas comme des exceptions à la règle générale.la source
await
empêche leAggregateException
wrapper.AggregateException
a été conçu pour la programmation parallèle et non pour la programmation asynchrone.Wait
était de se joindre à des instances de parallélisme de tâches dynamiquesTask
. IlTask
est dangereux de l' utiliser pour attendre des instances asynchrones . Microsoft a envisagé d'introduire un nouveau type «Promise», mais a choisi d'utiliser l'existant à laTask
place; le compromis de réutiliser leTask
type existant pour les tâches asynchrones est que vous vous retrouvez avec plusieurs API qui ne devraient tout simplement pas être utilisées dans du code asynchrone.Cela a du sens si
timeoutTask
c'est un produitTask.Delay
dont je crois ce que c'est dans le livre.Task.WhenAny
renvoieTask<Task>
, où la tâche interne est l'une de celles que vous avez passées en arguments. Cela pourrait être réécrit comme ceci:Dans les deux cas, car
downloadTask
a déjà terminé, il y a une très petite différence entrereturn await downloadTask
etreturn downloadTask.Result
. C'est en ce que ce dernier lanceraAggregateException
ce qui encapsulera toute exception d'origine, comme le souligne @KirillShlenskiy dans les commentaires. Le premier renverrait simplement l'exception d'origine.Dans les deux cas, quel que soit l'endroit où vous gérez des exceptions, vous devez de
AggregateException
toute façon rechercher et ses exceptions internes pour trouver la cause de l'erreur.la source