web-dev-qa-db-fra.com

Le mot clé Async en attente est-il équivalent à un lambda ContinueWith?

Quelqu'un pourrait-il avoir la gentillesse de confirmer si j'ai bien compris le mot clé Async wait? (Utilisation de la version 3 du CTP)

Jusqu'à présent, j'ai déterminé que l'insertion du mot clé wait avant un appel de méthode fait essentiellement 2 choses, A. Cela crée un retour immédiat et B. Il crée une "continuation" qui est invoquée à la fin de l'invocation de la méthode async. Dans tous les cas, la suite est le reste du bloc de code pour la méthode.

Donc, ce que je me demande, est-ce que ces deux bits de code sont techniquement équivalents, et si c'est le cas, cela signifie-t-il essentiellement que le mot-clé wait est identique à la création d'un ContinueWith Lambda (c'est-à-dire qu'il s'agit essentiellement d'un raccourci de compilation pour un)? Sinon, quelles sont les différences?

bool Success =
    await new POP3Connector(
        "mail.server.com", txtUsername.Text, txtPassword.Text).Connect();
// At this point the method will return and following code will
// only be invoked when the operation is complete(?)
MessageBox.Show(Success ? "Logged In" : "Wrong password");

CONTRE

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text ).Connect())
.ContinueWith((success) =>
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password"));
79
Maxim Gershkovich

L'idée générale est correcte - le reste de la méthode est transformée en une sorte de continuation.

Le article de blog "Fast Path" contient des détails sur le fonctionnement de la transformation du compilateur async/await.

Différences, du haut de ma tête:

Le mot clé await utilise également un concept de "contexte de planification". Le contexte de planification est SynchronizationContext.Current s'il existe, se replier sur TaskScheduler.Current. La suite est ensuite exécutée sur le contexte de planification. Donc une approximation plus proche serait de passer TaskScheduler.FromCurrentSynchronizationContext dans ContinueWith, se repliant sur TaskScheduler.Current si nécessaire.

L'implémentation réelle de async/await est basée sur la correspondance de modèles; il utilise un modèle "attendable" qui permet d'attendre d'autres choses que les tâches. Quelques exemples sont les API asynchrones WinRT, certaines méthodes spéciales telles que Yield, observables Rx et attendables socket spéciaux qui ne frappent pas le GC aussi fort . Les tâches sont puissantes, mais elles ne sont pas les seules à attendre.

Une autre différence mineure me vient à l'esprit: si l'attente est déjà terminée, la méthode async ne revient pas réellement à ce point; il continue de façon synchrone. C'est un peu comme passer TaskContinuationOptions.ExecuteSynchronously, mais sans les problèmes liés à la pile.

80
Stephen Cleary

C'est "essentiellement" cela, mais le code généré fait strictement plus que cela. Pour beaucoup plus de détails sur le code généré, je recommande fortement la série Eduasync de Jon Skeet:

http://codeblog.jonskeet.uk/category/eduasync/

En particulier, le post # 7 explique ce qui est généré (à partir de CTP 2) et pourquoi, donc probablement un bon ajustement pour ce que vous recherchez en ce moment:

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/

EDIT: Je pense que cela sera probablement plus détaillé que ce que vous recherchez dans la question, mais si vous vous demandez à quoi les choses ressemblent lorsque vous avez plusieurs attentes dans la méthode, cela est couvert dans le post # 9 :)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generated-code-for-multiple-awaits/

8
James Manning