Quelqu'un peut-il expliquer si await
et ContinueWith
sont synonymes ou non dans l'exemple suivant. J'essaye d'utiliser TPL pour la première fois et j'ai lu toute la documentation, mais je ne comprends pas la différence.
Attendez :
String webText = await getWebPage(uri);
await parseData(webText);
Continuer avec :
Task<String> webText = new Task<String>(() => getWebPage(uri));
Task continue = webText.ContinueWith((task) => parseData(task.Result));
webText.Start();
continue.Wait();
L'un est-il préféré à l'autre dans des situations particulières?
c#
task-parallel-library
task
async-await
Harrison
la source
la source
Wait
appel dans le second exemple , puis les deux extraits seraient équivalents ( la plupart du temps).getWebPage
méthode ne peut pas être utilisée dans les deux codes. Dans le premier code, il a unTask<string>
type de retour tandis que dans le second, il a unstring
type de retour. donc fondamentalement votre code ne se compile pas. - si pour être précis.Réponses:
Dans le deuxième code, vous attendez de manière synchrone que la poursuite se termine. Dans la première version, la méthode retournera à l'appelant dès qu'elle atteindra la première
await
expression qui n'est pas déjà terminée.Ils sont très similaires en ce sens qu'ils planifient tous les deux une continuation, mais dès que le flux de contrôle devient même légèrement complexe, cela
await
conduit à un code beaucoup plus simple. De plus, comme indiqué par Servy dans les commentaires, l'attente d'une tâche "déballe" les exceptions agrégées, ce qui conduit généralement à une gestion des erreurs plus simple. Utiliser égalementawait
planifiera implicitement la poursuite dans le contexte d'appel (sauf si vous utilisezConfigureAwait
). Ce n'est rien qui ne peut être fait "manuellement", mais c'est beaucoup plus facile de le faire avecawait
.Je vous suggère d'essayer d'implémenter une séquence d'opérations légèrement plus grande avec les deux
await
etTask.ContinueWith
- cela peut être une véritable révélation.la source
await
plusContinueWith
à cet égard.parseData
s'exécute.Voici la séquence d'extraits de code que j'ai récemment utilisés pour illustrer la différence et divers problèmes liés à l'utilisation de l'async.
Supposons que votre application basée sur l'interface graphique comporte un gestionnaire d'événements qui prend beaucoup de temps et que vous souhaitiez le rendre asynchrone. Voici la logique synchrone avec laquelle vous commencez:
LoadNextItem retourne une tâche, qui finira par produire un résultat que vous souhaitez inspecter. Si le résultat actuel est celui que vous recherchez, vous mettez à jour la valeur d'un compteur sur l'interface utilisateur et revenez à partir de la méthode. Sinon, vous continuez à traiter plus d'éléments à partir de LoadNextItem.
Première idée pour la version asynchrone: il suffit d'utiliser les continuations! Et ignorons la partie en boucle pour le moment. Je veux dire, qu'est-ce qui pourrait mal tourner?
Génial, maintenant nous avons une méthode qui ne bloque pas! Il plante à la place. Toutes les mises à jour des contrôles de l'interface utilisateur doivent se produire sur le thread de l'interface utilisateur, vous devrez donc en tenir compte. Heureusement, il existe une option pour spécifier comment les continuations doivent être planifiées, et il y en a une par défaut pour ceci:
Génial, maintenant nous avons une méthode qui ne plante pas! Il échoue à la place en silence. Les suites sont elles-mêmes des tâches distinctes, leur statut n'étant pas lié à celui de la tâche précédente. Ainsi, même si LoadNextItem échoue, l'appelant ne verra qu'une tâche qui s'est terminée avec succès. D'accord, alors transmettez simplement l'exception, s'il y en a une:
Génial, maintenant cela fonctionne réellement. Pour un seul article. Maintenant, que diriez-vous de cette boucle. Il s'avère qu'une solution équivalente à la logique de la version synchrone originale ressemblera à ceci:
Ou, au lieu de tout ce qui précède, vous pouvez utiliser async pour faire la même chose:
C'est beaucoup plus agréable maintenant, n'est-ce pas?
la source