Il fonctionne de manière similaire au mot-clé yield return
dans C# 2.0.
Une méthode asynchrone n'est pas réellement une méthode séquentielle ordinaire. Il est compilé dans une machine d'état (un objet) avec un certain état (les variables locales sont transformées en champs de l'objet). Chaque bloc de code entre deux utilisations de await
est une "étape" de la machine d'état. Cela signifie que lorsque la méthode démarre, elle exécute simplement la première étape, puis la machine d'état renvoie et planifie un travail à effectuer. Lorsque le travail est terminé, elle exécute l'étape suivante de la machine d'état. Par exemple, ce code:
async Task Demo() {
var v1 = foo();
var v2 = await bar();
more(v1, v2);
}
sera traduit à quelque chose comme:
class _Demo {
int _v1, _v2;
int _state = 0;
Task<int> _await1;
public void Step() {
switch(this._state) {
case 0:
this._v1 = foo();
this._await1 = bar();
// When the async operation completes, it will call this method
this._state = 1;
op.SetContinuation(Step);
case 1:
this._v2 = this._await1.Result; // Get the result of the operation
more(this._v1, this._v2);
}
}
L'important est qu'il utilise juste la méthode SetContinuation
de préciser que lorsque l'opération est terminée, il doit appeler la Step
méthode à nouveau (et la méthode sait qu'il devrait exécuter le second bit du code original en utilisant le champ _state
). Vous pouvez facilement imaginer que le SetContinuation
serait quelque chose comme btn.Click += Step
, qui fonctionnerait complètement sur un seul thread. Le modèle de programmation asynchrone en C# est très proche des workflows asynchrones F # (en fait, c'est essentiellement la même chose, mis à part quelques détails techniques), et l'écriture d'applications GUI monothread réactives en utilisant async
est une zone assez intéressante - au moins je le pense - voir par exemple this article (peut-être que je devrais écrire une version C# maintenant :-)).
La traduction est similaire aux itérateurs (et yield return
) et en fait, il était possible d'utiliser des itérateurs pour implémenter la programmation asynchrone en C# plus tôt. J'ai écrit an article about that il y a quelques temps - et je pense que cela peut encore vous donner un aperçu de la façon dont la traduction fonctionne.
Comment est-il programmé sans thread séparé? Une continuation est-elle un concept spécifique dans le CLR qui permet une planification légère? –
@ 0xA3: Je crois que le document dit que la méthode async ne fonctionne pas sur son propre thread. C'est à dire. Tout comme TPL, il s'agira d'un mélange des threads actuels du thread et du pool de threads en fonction de la situation. –