82 votes

À quoi sert la nouvelle fonctionnalité C# await ?

Quelqu'un peut-il expliquer ce que le await fait ?

62voto

RTigger Points 979

Ils ont juste Nous en avons parlé au PDC hier !

Await est utilisé en conjonction avec Tasks (programmation parallèle) dans .NET. Il s'agit d'un mot-clé qui sera introduit dans la prochaine version de .NET. Il permet plus ou moins de "mettre en pause" l'exécution d'une méthode pour attendre la fin de l'exécution de la tâche. Voici un bref exemple :

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();

47voto

KeithS Points 36130

En gros, le async et await vous permettent de spécifier que l'exécution d'une méthode doit s'arrêter à toutes les utilisations de await qui marquent les appels de méthodes asynchrones, puis reprennent une fois l'opération asynchrone terminée. Cela vous permet d'appeler une méthode dans le thread principal d'une application et de traiter des tâches complexes de manière asynchrone, sans avoir à définir explicitement des threads et des jointures ou à bloquer le thread principal de l'application.

Pensez-y comme étant un peu similaire à un yield return dans une méthode produisant un IEnumerable. Lorsque le runtime rencontre le yield il sauvegarde l'état actuel de la méthode et renvoie la valeur ou la référence cédée. La prochaine fois que IEnumerator.MoveNext() est appelé sur l'objet de retour (qui est généré en interne par le runtime), l'ancien état de la méthode est restauré sur la pile et l'exécution continue avec la ligne suivante après la balise yield return comme si nous n'avions jamais quitté la méthode. Sans ce mot-clé, un type IEnumerator doit être défini sur mesure pour stocker l'état et gérer les demandes d'itération, avec des méthodes qui peuvent devenir TRÈS complexes.

De même, une méthode marquée comme async doit avoir au moins un await . Sur un await le runtime sauvegarde l'état et la pile d'appels du thread en cours, effectue l'appel asynchrone, puis revient à la boucle de messages du runtime pour traiter le message suivant et maintenir la réactivité de l'application. Une fois l'opération asynchrone terminée, lors de la prochaine opportunité de planification, la pile d'appel de l'opération asynchrone est repoussée et poursuivie comme si l'appel était synchrone.

Ainsi, ces deux nouveaux mots-clés simplifient essentiellement le codage des processus asynchrones, tout comme yield return a simplifié la génération d'énumérables personnalisés. Avec quelques mots-clés et un peu de connaissances de base, vous pouvez vous passer de tous les détails déroutants et souvent sources d'erreurs d'un modèle asynchrone traditionnel. Ceci sera INVALABLE dans presque toutes les applications GUI pilotées par événements comme Winforms, WPF ou Silverlight.

31voto

Anri Points 3545

La réponse actuellement acceptée est trompeuse. await ne met rien en pause. Tout d'abord, il ne peut être utilisé que dans les méthodes ou lambdas marquées comme async et renvoyant Task ou void si vous ne vous souciez pas d'avoir Task en cours d'exécution dans cette méthode.

En voici une illustration :

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}

Sortie :

Entré dans DoWork(). Dormir 3
tâche asynchrone itération 0
Statut de la tâche : WaitingForActivation
En attente d'ENTER
tâche asynchrone itération 1
tâche asynchrone itération 2
tâche asynchrone itération 3
tâche asynchrone itération 4
tâche asynchrone itération 5
tâche asynchrone itération 6
tâche asynchrone itération 7
tâche asynchrone itération 8
itération de tâches asynchrones 9
Sortie de DoWork()

11voto

Todd Menier Points 3599

Pour ceux qui ne connaissent pas la programmation asynchrone dans .NET, voici une analogie (totalement fausse) dans un scénario qui vous est peut-être plus familier : les appels AJAX utilisant JavaScript/jQuery. Un simple message AJAX jQuery ressemble à ceci :

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});

La raison pour laquelle nous traitons les résultats dans une fonction de rappel est que nous ne bloquons pas le thread actuel en attendant le retour de l'appel AJAX. Ce n'est que lorsque la réponse est prête que la fonction de rappel est lancée, et éventuellement sur un autre thread.

Maintenant, si JavaScript supportait le await (ce qui n'est bien sûr pas le cas), vous pourriez obtenir le même résultat avec ceci :

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here

C'est beaucoup plus propre, mais on dirait bien que nous avons introduit du code synchrone et bloquant. Mais le (faux) compilateur JavaScript aurait pris tout ce qui suit await et l'a intégré dans une fonction de rappel, de sorte qu'au moment de l'exécution, le deuxième exemple se comporte exactement comme le premier.

Cela peut sembler ne pas vous épargner beaucoup de travail, mais lorsqu'il s'agit de choses telles que la gestion des exceptions et les contextes de synchronisation, le compilateur fait en réalité une lot de la lourde tâche pour vous. Pour en savoir plus, je vous recommande le FAQs suivi par Série de blogs de Stephen Cleary .

2voto

adrift Points 24386

Regardez "L'avenir de C# et Visual Basic", la présentation d'Anders Hejlsberg à PDC 2010 où il traite de ce sujet et donne quelques démos sympas.

Si vous voulez jouer avec maintenant, vous pouvez obtenir le CTP VS Async. ici .

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