Comment est-ce que C# 5.0 asynchrone-attendent fonction diffère de la TPL?
Je ne vois pas la différence entre C#(et VB s) nouveau async fonctionnalités, et .NET 4.0 Task Parallel Library. Prenez, par exemple, Eric Lippert du code à partir 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 la await
mot-clé sert à deux fins. La première occurrence (FetchAsync
) semble signifier, "Si cette valeur est utilisée plus tard dans la méthode et sa tâche n'est pas terminée, attendez jusqu'à ce qu'elle se termine avant de continuer." La deuxième instance (archive
) semble signifier, "Si cette tâche n'est pas encore terminé, attendez maintenant jusqu'à la fin." Si je me trompe, corrigez-moi.
Ne pourrait-elle pas tout aussi bien être écrit comme ceci?
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é la première await
avec un Task.Result
où la valeur est réellement nécessaire, et la deuxième await
avec Task.Wait()
, où l'attente est en train de se produire. La fonctionnalité est (1)
déjà mis en œuvre, et (2)
beaucoup plus proche sémantiquement à ce qui se passe réellement dans le code.
Je me rends compte qu'un async
méthode est réécrit comme une machine d'état, semblables à des itérateurs, mais je ne vois pas quels sont les avantages que cela implique. Tout code qui nécessite un autre thread pour fonctionner (comme le téléchargement) auront encore besoin d'un autre thread, et tout le code qui ne fonctionne pas (comme la lecture à partir d'un fichier) pourrait encore utiliser le TPL de travailler avec un seul thread.
Je suis évidemment manquant de quelque chose d'énorme ici; quelqu'un peut-il m'aider à comprendre un peu mieux?
- Voir aussi stackoverflow.com/questions/3513432/... et stackoverflow.com/questions/12414601/...
- Voir ce lien qui a soigné des exemples: richnewman.wordpress.com/2012/12/03/...
Vous devez vous connecter pour publier un commentaire.
Je pense que le malentendu se pose ici:
C'est en fait tout à fait incorrect. Ces deux ont le même sens.
Dans votre premier cas:
Ce qui se passe ici, c'est que le runtime dit "Commencer à appeler FetchAsync, puis retourne le point de l'exécution du thread appelant cette méthode." Il n'y a pas de "en attente" ici - à la place, l'exécution retourne à l'appelant contexte de synchronisation, et les choses ressasser. À un certain moment dans l'avenir, FetchAsync sa Tâche terminée, et à ce point, ce code va reprendre sur le thread appelant contexte de synchronisation, et de la prochaine instruction (affectation de la variable de document) va se produire.
Exécution continuera ensuite jusqu'à la deuxième attendent d'appel à laquelle, la même chose va se produire - si le
Task<T>
(archive) n'est pas complète, l'exécution sera libéré dans le contexte de l'appel - dans le cas contraire, l'archive sera réglé.Dans le second cas, les choses sont très différentes - ici, vous êtes bloque, ce qui signifie que l'appelant contexte de synchronisation n'obtiendrez jamais une chance d'exécuter le code jusqu'à ce que l'ensemble de votre méthode est terminée. Certes, il y est encore asynchronisme, mais l'asynchronie est entièrement contenue à l'intérieur de ce bloc de code pas de code en dehors de cette collé le code qui va se passer sur ce thread jusqu'à ce que l'ensemble de votre code terminée.
Il y a une énorme différence:
Wait()
blocs,await
ne bloque pas. Si vous exécutez la version asynchrone deArchiveDocuments()
sur votre thread GUI, au GUI va rester sensible alors que l'extraction et l'archivage des opérations sont en cours d'exécution.Si vous utilisez le TPL version avec
Wait()
, de votre interface sera bloqué.Noter que
async
parvient à le faire sans introduire de fils - point de laawait
, le contrôle est simplement retourné à la boucle de message. Une fois la tâche attendu est terminée, le reste de la méthode (suite) est mis en file d'attente sur la boucle de message et le thread GUI continuera de fonctionnerArchiveDocuments
où il l'a laissée.Anders bouilli vers le bas pour une très brève réponse dans le Canal 9 interview en Direct qu'il a fait. Je le recommande fortement
La nouvelle Async et await mots-clés vous permettent de orchestrer la simultanéité dans vos applications. Ils n'ont pas fait introduire toute la simultanéité dans votre application.
TPL et plus précisément la Tâche est une façon vous pouvez utiliser pour effectuer les opérations simultanément. La nouvelle async et await mots clés vous permettent de composer ces opérations simultanées dans un "synchrone" ou "linéaire" de la mode.
De sorte que vous pouvez toujours écrire un linéaire de flux de contrôle dans vos programmes, tandis que le calcul peut ou peut ne pas se produire simultanément. Lorsque le calcul ne se produire simultanément, attendent et async vous permettent de composer ces opérations.
La capacité de transformer le programme de flux de contrôle dans une machine d'état est ce qui rend ces nouveaux mots-clés intéressant. Il pense que cession du contrôle, plutôt que de valeurs.
Découvrez ce Canal 9 de la vidéo de Anders parler de la nouvelle fonction.
Le problème ici est que la signature de
ArchiveDocuments
est trompeuse. Il a un retour explicite devoid
mais vraiment le retour estTask
. Pour moi nulle implique synchrone comme il n'existe aucun moyen "d'attendre" la fin de la. Considérer l'autre signature de la fonction.Pour moi quand c'est écrit de cette façon, la différence est beaucoup plus évident. Le
ArchiveDocuments
fonction n'est pas celle qui se termine de façon synchrone mais de le terminer plus tard.ArchiveDocuments()
ressembleraitTask task = ArchiveDocuments(List<Url> urls);
? Cela ne semble pas juste... et si je comprends bien, l'appelant n'est pas vraiment s'attendre à tout. En effet, si l'on se soucie de l'issue deArchiveDocuments()
, l'ensemble du scénario tombe à l'eau et ne fonctionne pas.Task
est également de retour valable.L'appel à
FetchAsync()
va encore bloquer jusqu'à la fin (à moins d'une déclaration dans les appelsawait
?) La clé est que le contrôle est renvoyé à l'appelant (parce que leArchiveDocuments
méthode elle-même est déclarée commeasync
). Si l'appelant peut être heureux et de continuer le traitement logique de l'INTERFACE utilisateur, répondre à des événements, etc.Quand
FetchAsync()
se termine, il interrompt l'appelant pour terminer la boucle. Il frappeArchiveAsync()
et de blocs, maisArchiveAsync()
probablement juste de crée une nouvelle tâche, il commence, et renvoie la tâche. Cela permet à la deuxième boucle pour commencer, et que la tâche est en cours de traitement.La deuxième boucle hits
FetchAsync()
et de blocs, de rendre le contrôle à l'appelant. LorsqueFetchAsync()
complète, une fois encore, les interruptions de l'appelant à poursuivre le traitement. Il frappe ensuiteawait archive
, qui retourne le contrôle à l'appelant jusqu'à ce que leTask
créé dans la boucle 1 est terminée. Une fois que la tâche est terminée, l'appelant est de nouveau interrompue, et la deuxième boucle appelsArchiveAsync()
, qui est une tâche lancée et commence la boucle 3, répétez les ad nauseam.La clé est de rendre le contrôle à l'appelant si le lourd poussoirs sont en cours d'exécution.
await
ed méthode n'a pas besoin de lancer ou de planifier quoi que ce soit. Ce qui m'a incité à faire cette déclaration a été de laarchive.Wait()
. Dans cet exemple, le code est certainement écrit à attendre qu'un thread pour faire quelque chose d'immédiatement et complète. Ma déclaration a été dans le cadre de cet exemple, seulement.Le mot clé await ne pas introduire de la concurrence. C'est comme le mot clé yield, il indique au compilateur de restructurer votre code en lambda contrôlé par une machine d'état.
De voir ce qui attend les code ressemblerait sans "attendre" voir cet excellent lien: http://blogs.msdn.com/b/windowsappdev/archive/2012/04/24/diving-deep-with-winrt-and-await.aspx