59 votes

C# 5 Async/Await - est-il *simultanées*?

J'ai vu les nouvelles async trucs en C# 5, et une question en particulier est venu.

Je comprends que l' await mot-clé est un pur compilateur truc/sucre syntaxique pour mettre en œuvre la poursuite de passage, où le reste de la méthode est divisée en Task objets et en file d'attente jusqu'à être exécutées dans l'ordre, mais où le contrôle est retourné à la méthode appelante.

Mon problème est que j'ai entendu dire qu'actuellement, c'est tous sur un seul thread. Est-ce à dire que cette async truc est vraiment juste une façon de transformer la poursuite de code en Task objets, puis en appelant Application.DoEvents() après chaque tâche est terminée avant de commencer le prochain?

Ou ai-je raté quelque chose? (Cette partie de la question est rhétorique - je suis pleinement conscient que je suis absent quelque chose :) )

Merci beaucoup à l'avance.

58voto

Stephen Cleary Points 91731

Il est simultanées, dans le sens que beaucoup de circulation asychronous opérations peuvent être en cours à tout moment. Il peut ou peut ne pas être multithread.

Par défaut, await de planifier la poursuite de retour à la "contexte d'exécution en cours". Le "contexte d'exécution en cours" est défini comme SynchronizationContext.Current si elle est non-nullou TaskScheduler.Current si il n'y a pas d' SynchronizationContext.

Vous pouvez remplacer ce comportement par défaut en appelant ConfigureAwait et en passant false de la continueOnCapturedContext paramètre. Dans ce cas, la poursuite ne sera pas prévu de retour à celle du contexte d'exécution. Généralement, cela signifie qu'il sera exécuté sur un pool de threads thread.

Sauf si vous écrivez le code de bibliothèque, le comportement par défaut est exactement ce qui est souhaité. WinForms, WPF et Silverlight (c'est à dire, tous les cadres de l'INTERFACE utilisateur) offre un SynchronizationContext, de sorte que la poursuite s'exécute sur le thread d'INTERFACE utilisateur (et peut accéder en toute sécurité des objets d'INTERFACE utilisateur). ASP.NET elle fournit également une SynchronizationContext qui garantit la poursuite s'exécute dans le bon contexte de demande.

Les autres threads (y compris le pool de threads les threads, Thread, et BackgroundWorker) ne fournissent pas un SynchronizationContext. Donc la Console d'applications et de services Win32 par défaut n'ont pas d' SynchronizationContext . Dans cette situation, les continuations exécuter sur le pool de threads les threads. C'est pourquoi l'application de Console démonstrations à l'aide de await/async inclure un appel à l' Console.ReadLine/ReadKey ou de faire un blocage Wait sur Task.

Si vous vous trouvez dans le besoin d'un SynchronizationContext, vous pouvez utiliser AsyncContext de mon Nito.AsyncEx bibliothèque; qu'il est fondamentalement juste donne un async-compatible "boucle principale" avec un SynchronizationContext. Je trouve ça utile pour la Console d'applications et de tests unitaires (VS2012 a maintenant un support intégré pour l' async Task tests unitaires).

Pour plus d'informations sur l' SynchronizationContext, voir mon Fév article MSDN.

À aucun moment, DoEvents ou l'équivalent; plutôt, le contrôle des flux de retours tous le moyen de sortir, et de la poursuite (le reste de la fonction) est planifié pour être exécuté plus tard. C'est une solution plus propre, car il ne cause pas de réentrée questions comme vous l'avez si DoEvents a été utilisé.

5voto

Polynomial Points 12830

L'idée derrière async/await, c'est qu'il effectue continuation en passant bien, et de ne pas allouer un nouveau thread pour l'opération. La poursuite peut se produire sur un nouveau thread, il peut continuer sur le même thread.

2voto

xanatos Points 30513

La vraie "viande" (asynchrone) de la partie de async/await est généralement effectué séparément et de la communication à l'appelant se fait par le biais de TaskCompletionSource. Comme écrit ici http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx

Le TaskCompletionSource type sert à deux fins, à la fois fait allusion à son nom: c'est une source pour la création d'une tâche, et la source de cette tâche d'achèvement. En essence, un TaskCompletionSource agit en tant que producteur pour une Tâche et de son achèvement.

et l'exemple est tout à fait clair:

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException("function"); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

Par le biais de l' TaskCompletionSource vous avez accès à un Task objet que vous pouvez attendre, mais ce n'est pas par le biais de la async/await mots-clés que vous avez créé le multithreading.

Notez que lorsque beaucoup de "ralentir" les fonctions seront convertis à la async/await syntaxe, vous n'aurez pas besoin d'utiliser TaskCompletionSource très bien. Ils vont l'utiliser en interne (mais à la fin, quelque part il doit y avoir un TaskCompletionSource d'avoir un asynchrones suite)

1voto

Aaron Murgatroyd Points 857

La façon dont je veux expliquer c'est que le "en attente de" mot-clé attend simplement une tâche à terminer, mais les rendements de l'exécution du thread appelant pendant qu'il attend. Elle renvoie ensuite le résultat de la Tâche et continue à partir de la déclaration après le "en attente de" mot-clé une fois la Tâche terminée.

Certaines personnes que j'ai remarqué semblent penser que la Tâche est exécutée dans le même fil que le thread appelant, c'est incorrect et peut être prouvée par une tentative de modifier un Windows.Les formes GUI élément à l'intérieur de la méthode qui attendent les appels. Toutefois, la poursuite est exécuté dans le thread appelant.

C'est juste un moyen sympa de ne pas avoir à subir de rappel des délégués ou des gestionnaires d'événements pour quand la Tâche est terminée.

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