Les réponses de SLaks et Killercam sont bonnes; Je pensais simplement ajouter un peu plus de contexte.
Votre première question porte essentiellement sur les méthodes qui peuvent être marquées async
.
Une méthode marquée comme async
peut retourner void
, Task
ou Task<T>
. Quelles sont les différences entre eux?
Une Task<T>
méthode asynchrone de retour peut être attendue, et lorsque la tâche sera terminée, elle proposera un T.
Une Task
méthode asynchrone de retour peut être attendue, et lorsque la tâche est terminée, la poursuite de la tâche est planifiée pour s'exécuter.
UNE void
méthode asynchrone de retour ne peut pas être attendue; c'est une méthode "feu et oublie". Cela fonctionne de manière asynchrone et vous n'avez aucun moyen de savoir quand cela est fait. C'est plus qu'un peu bizarre; comme le dit SLaks, vous ne feriez normalement cela que lorsque vous créez un gestionnaire d'événements asynchrone. L'événement se déclenche, le gestionnaire s'exécute; personne ne va "attendre" la tâche retournée par le gestionnaire d'événements parce que les gestionnaires d'événements ne retournent pas de tâches, et même s'ils l'ont fait, quel code utiliserait la tâche pour quelque chose? Ce n'est généralement pas le code utilisateur qui transfère le contrôle au gestionnaire en premier lieu.
Votre deuxième question, dans un commentaire, porte essentiellement sur ce qui peut être await
édité:
Quels types de méthodes peuvent être await
édités? Une méthode de retour des annulations peut-elle être utilisée await
?
Non, une méthode de retour de null ne peut pas être attendue. Le compilateur se traduit await M()
par un appel à M().GetAwaiter()
, où GetAwaiter
peut être une méthode d'instance ou une méthode d'extension. La valeur attendue doit être celle pour laquelle vous pouvez obtenir un serveur; clairement une méthode de retour de vide ne produit pas de valeur à partir de laquelle vous pouvez obtenir un serveur.
Task
-les méthodes de retour peuvent produire des valeurs attendues. Nous prévoyons que des tiers voudront créer leurs propres implémentations d' Task
objets similaires qui peuvent être attendus, et vous pourrez les attendre. Cependant, vous ne serez pas autorisé à déclarer des async
méthodes qui renvoient autre chose que void
, Task
ou Task<T>
.
(MISE À JOUR: Ma dernière phrase peut être falsifiée par une future version de C #; il existe une proposition d'autoriser des types de retour autres que les types de tâches pour les méthodes asynchrones.)
(MISE À JOUR: la fonctionnalité mentionnée ci-dessus a été intégrée à C # 7.)
async void
les méthodes lèvent leur exception sur leSynchronizationContext
qui était actif au moment où elles ont commencé à s'exécuter. Ceci est similaire au comportement des gestionnaires d'événements (synchrones). @DrewMarsh: leUnobservedTaskException
paramètre d'exécution et ne s'applique qu'aux méthodes de tâche asynchrone "feu et oublie" , pas auxasync void
méthodes.Dans le cas où l'appelant souhaite attendre la tâche ou ajouter une suite.
En fait, la seule raison de revenir
void
est si vous ne pouvez pas revenirTask
car vous écrivez un gestionnaire d'événements.la source
void
, vous n'avez aucun moyen d'accéder à la tâche qu'elle génère. (En fait, je ne sais pas si cela génère même unTask
du tout)Les méthodes retournant
Task
etTask<T>
sont composables - ce qui signifie que vous pouvezawait
les utiliser à l'intérieur d'uneasync
méthode.async
Les méthodes qui retournentvoid
ne sont pas composables, mais elles ont deux autres propriétés importantes:Le deuxième point est important lorsque vous avez affaire à un contexte qui maintient un décompte d'opérations asynchrones en cours.
Le contexte ASP.NET est l'un de ces contextes; si vous utilisez des
Task
méthodes asynchrones sans les attendre d'une asynchronevoid
méthode , la requête ASP.NET sera exécutée trop tôt.Un autre contexte est celui que
AsyncContext
j'ai écrit pour les tests unitaires (disponible ici ) - laAsyncContext.Run
méthode suit le nombre d'opérations en cours et retourne quand il est à zéro.la source
Le type
Task<T>
est le type de bête de somme de la bibliothèque parallèle de tâches (TPL), il représente le concept de "un travail / travail qui va produire un résultat de typeT
dans le futur". Le concept de «travail qui se terminera dans le futur mais ne renvoie aucun résultat» est représenté par le type de tâche non générique.Précisément comment le résultat de type
T
va être produit et les détails de mise en œuvre d'une tâche particulière; le travail peut être transféré vers un autre processus sur la machine locale, vers un autre thread, etc. Les tâches TPL sont généralement transférées vers des threads de travail à partir d'un pool de threads dans le processus actuel, mais ce détail d'implémentation n'est pas fondamental pour leTask<T>
type; plutôt aTask<T>
peut représenter toute opération à latence élevée qui produit unT
.Basé sur votre commentaire ci-dessus:
L'
await
expression signifie "évaluer cette expression pour obtenir un objet représentant un travail qui produira à l'avenir un résultat. Inscrivez le reste de la méthode actuelle comme rappel associé à la poursuite de cette tâche. Une fois cette tâche produite et le rappel est inscrit, retourne immédiatement le contrôle à mon interlocuteur ". Ceci est opposé / contrairement à un appel de méthode normal, qui signifie "souvenez-vous de ce que vous faites, exécutez cette méthode jusqu'à ce qu'elle soit complètement terminée, puis reprenez là où vous vous êtes arrêté, connaissant maintenant le résultat de la méthode".Edit: Je devrais citer l'article d'Eric Lippert en octobre 2011 dans MSDN Magazine car cela m'a beaucoup aidé à comprendre ce genre de choses en premier lieu.
Pour plus d'informations et de pages blanches, cliquez ici .
J'espère que cela vous aidera.
la source