63 votes

En quoi la fonctionnalité async-await de C# 5.0 diffère-t-elle de la TPL ?

Je ne vois pas la différence entre les nouvelles fonctionnalités asynchrones de C# (et de VB) et celles de .NET 4.0. Bibliothèque parallèle des tâches . Prenez, par exemple, le code d'Eric Lippert d'ici :

async void ArchiveDocuments(List<Url> urls) {
    Task archive = null;
    for(int i = 0; i < urls.Count; ++i) {
        var document = await FetchAsync(urls[i]);
        if (archive != null)
            await archive;
        archive = ArchiveAsync(document);
    }
}

Il semble que le await mot-clé sert deux objectifs différents. La première occurrence ( FetchAsync ) semble vouloir dire, "Si cette valeur est utilisée plus tard dans la méthode et que sa tâche n'est pas terminée, attendez qu'elle se termine avant de continuer." La deuxième instance ( archive ) semble vouloir dire, "Si cette tâche n'est pas encore terminée, attendez à l'heure actuelle jusqu'à ce qu'il soit terminé." Si je me trompe, veuillez me corriger.

Ne pourrait-on pas tout aussi bien l'écrire comme ça ?

void ArchiveDocuments(List<Url> urls) {
    for(int i = 0; i < urls.Count; ++i) {
        var document = FetchAsync(urls[i]);       // removed await
        if (archive != null)
            archive.Wait();                       // changed to .Wait()
        archive = ArchiveAsync(document.Result);  // added .Result
    }
}

J'ai remplacé le premier await avec un Task.Result où la valeur est réellement nécessaire, et la seconde await con Task.Wait() où l'attente se produit réellement. La fonctionnalité est (1) déjà mis en œuvre, et (2) beaucoup plus proche sémantiquement de ce qui se passe réellement dans le code.

Je réalise qu'une async est réécrite comme une machine à état, similaire aux itérateurs, mais je ne vois pas non plus quels avantages cela apporte. Tout code qui nécessite un autre thread pour fonctionner (comme le téléchargement) nécessitera toujours un autre thread, et tout code qui ne le nécessite pas (comme la lecture d'un fichier) pourrait toujours utiliser la TPL pour fonctionner avec un seul thread.

Je suis manifestement en train de rater quelque chose d'énorme ici ; quelqu'un peut-il m'aider à comprendre un peu mieux ?

0 votes

0 votes

Voir ce lien qui contient de bons exemples : richnewman.wordpress.com/2012/12/03/

71voto

Reed Copsey Points 315315

Je pense que le malentendu se situe ici :

Il semble que le mot-clé await serve deux objectifs différents. La première occurrence (FetchAsync) semble signifier : "Si cette valeur est utilisée plus tard dans la méthode et que sa tâche n'est pas terminée, attendez qu'elle se termine avant de continuer." La deuxième occurrence (archive) semble signifier, "Si cette tâche n'est pas encore terminée, attendez maintenant qu'elle se termine". Si je me trompe, veuillez me corriger.

C'est en fait complètement faux. Les deux ont la même signification.

Dans votre premier cas :

var document = await FetchAsync(urls[i]);

Ce qui se passe ici, c'est que le runtime dit "Commence à appeler FetchAsync, puis renvoie le point d'exécution actuel au thread qui appelle cette méthode". Il n'y a pas d'"attente" ici - au lieu de cela, l'exécution retourne au contexte de synchronisation appelant, et les choses continuent à tourner. À un moment donné dans le futur, la tâche de FetchAsync se terminera, et à ce moment-là, ce code reprendra sur le contexte de synchronisation du thread appelant, et l'instruction suivante (assignation de la variable document) se produira.

L'exécution se poursuivra ensuite jusqu'au deuxième appel await - à ce moment-là, la même chose se produira - si la fonction Task<T> (archive) n'est pas complet, l'exécution sera libérée au contexte appelant - sinon, l'archive sera fixée.

Dans le second cas, les choses sont très différentes - ici, vous bloquez explicitement, ce qui signifie que le contexte de synchronisation appelant n'aura jamais la chance d'exécuter un quelconque code avant que votre méthode entière ne soit terminée. Certes, il y a toujours de l'asynchronie, mais elle est complètement contenue dans ce bloc de code - aucun code en dehors de ce code collé ne se produira sur ce thread avant que tout votre code ne soit terminé.

26voto

Brad Cunningham Points 3835

Anders l'a résumé en une réponse très succincte dans l'interview qu'il a donnée à Channel 9 Live. Je le recommande vivement

Les nouveaux mots-clés Async et await vous permettent de orchestrer la simultanéité dans vos applications. Ils n'introduisent pas réellement de concurrence dans votre application.

TPL et plus particulièrement Task est un sens que vous pouvez utiliser pour effectuer réellement des opérations simultanées. Les nouveaux mots-clés async et await vous permettent de composer ces opérations simultanées de manière "synchrone" ou "linéaire".

Vous pouvez donc toujours écrire un flux de contrôle linéaire dans vos programmes, alors que le calcul réel peut ou non se faire de manière simultanée. Lorsque le calcul se fait en même temps, await et async vous permettent de composer ces opérations.

3 votes

Ce n'est pas vraiment dites quelque chose, n'est-ce pas ? Permettez-moi de reformuler : en quoi cela répond-il à la question posée ?

13 votes

La question est la suivante : "En quoi la fonctionnalité async-await de C# 5.0 diffère-t-elle de la TPL ?". Ma réponse est appropriée pour cette question IMO

25voto

Daniel Points 7960

Il y a une énorme différence :

Wait() blocs, await ne bloque pas. Si vous exécutez la version asynchrone de ArchiveDocuments() sur votre thread GUI, l'interface graphique restera réactive pendant que les opérations de récupération et d'archivage sont en cours. Si vous utilisez la version TPL avec Wait() votre interface graphique sera bloquée.

Notez que async parvient à le faire sans introduire de fils - au moment de la await le contrôle est simplement renvoyé à la boucle de messages. Une fois que la tâche attendue est terminée, le reste de la méthode (continuation) est mis en file d'attente dans la boucle de messages et le thread de l'interface graphique continue de fonctionner. ArchiveDocuments où il s'est arrêté.

6voto

John Leidegren Points 21951

La possibilité de transformer le flux de contrôle du programme en une machine à états est ce qui rend ces nouveaux mots-clés intéressants. Pensez-y comme contrôle des rendements plutôt que des valeurs.

Vérifiez cette vidéo de Channel 9 d'Anders parlant de la nouvelle fonctionnalité.

4voto

JaredPar Points 333733

Le problème ici est que la signature de ArchiveDocuments est trompeuse. Il y a un retour explicite de void mais en réalité le retour est Task . Pour moi, void implique une fonction synchrone, car il n'y a aucun moyen d'"attendre" qu'elle se termine. Considérez la signature alternative de la fonction.

async Task ArchiveDocuments(List<Url> urls) { 
  ...
}

Pour moi, quand c'est écrit de cette façon, la différence est beaucoup plus évidente. Le site ArchiveDocuments n'est pas une fonction qui se termine de manière synchrone mais qui se terminera plus tard.

2 votes

Ce code aurait beaucoup plus de sens si "archive" était une variable membre ou statique, et non définie dans la méthode... Ceci étant dit, les fonctions asynchrones à retour nul sont parfaitement valables et acceptables, et ont une signification "feu et oublie", selon la documentation de la spécification.

0 votes

Vous voulez dire que l'appel à ArchiveDocuments() ressemblerait à Task task = ArchiveDocuments(List<Url> urls); ? Cela ne semble pas correct... et si je comprends bien, l'appelant n'attend pas vraiment. En fait, s'il se soucie du résultat de l'opération ArchiveDocuments() le scénario entier s'écroule et ne fonctionne pas.

1 votes

@Reed, je suis d'accord qu'ils sont effectivement valides et corrects. Je trouve juste que c'est très trompeur et un peu présomptueux comme peut-être je ne veux pas oublier ;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X