Flux de contrôle dans les programmes Async (C# et Visual Basic)

Vous pouvez écrire et gérer des programmes asynchrones plus facilement à l'aide des mots clés Async et Await .Toutefois, les résultats peuvent vous étonner si vous n'incluez pas comment votre programme s'exécute.Cette rubrique suit l'ordre d'exécution via un programme async simple pour vous indiquer lorsque le contrôle se déplace d'une méthode à une autre et les informations sont transférées à chaque fois.

[!REMARQUE]

Les mots clés d' Async et d' Await ont été introduits dans Visual Studio 2012.Pour plus d'informations sur de nouvelles fonctionnalités dans cette version, consultez Nouveautés de Visual Studio 2012.

En général vous marquez les méthodes qui contiennent le code asynchrone avec le modificateur Async (Visual Basic) ou async (C#) .Dans une méthode qui est marquée avec un modificateur async, vous pouvez utiliser un opérateur Await (Visual Basic) ou await (C#) pour spécifier où la méthode suspend pour attendre un processus appelé asynchrone se termine.Pour plus d'informations, consultez Programmation asynchrone avec Async et Await (C# et Visual Basic).

L'exemple suivant utilise les méthodes async pour télécharger le contenu d'un site Web spécifié en tant que chaîne et afficher la longueur de la chaîne.Cet exemple de code contient les deux méthodes suivantes:

  • startButton_Click, qui appelle AccessTheWebAsync et affiche le résultat.

  • AccessTheWebAsync, qui télécharge le contenu d'un site Web comme une chaîne et retourne la longueur de la chaîne.AccessTheWebAsync utilise une méthode asynchrone HttpClient , GetStringAsync(String), pour télécharger le contenu.

Les lignes d'affichage comptées apparaissent aux points stratégiques dans tout le programme pour vous aider à comprendre comment le programme s´exécute et à expliquer ce qui se produit à chaque point marqué.Les lignes d'affichage sont étiquetées « ONE » à « SIX ». Les étiquettes représentent l'ordre dans lequel le programme atteint ces lignes de code.

Le code suivant illustre un plan du programme.

Class MainWindow

    Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click

        ' ONE
        Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()

        ' FOUR
        Dim contentLength As Integer = Await getLengthTask

        ' SIX
        ResultsTextBox.Text &=
            String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)

    End Sub


    Async Function AccessTheWebAsync() As Task(Of Integer)

        ' TWO
        Dim client As HttpClient = New HttpClient() 
        Dim getStringTask As Task(Of String) = 
            client.GetStringAsync("https://msdn.microsoft.com")

        ' THREE
        Dim urlContents As String = Await getStringTask

        ' FIVE
        Return urlContents.Length
    End Function

End Class
public partial class MainWindow : Window
{
    // . . .
    private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        // ONE
        Task<int> getLengthTask = AccessTheWebAsync();

        // FOUR
        int contentLength = await getLengthTask;

        // SIX
        resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
    }


    async Task<int> AccessTheWebAsync()
    {
        // TWO
        HttpClient client = new HttpClient();
        Task<string> getStringTask =
            client.GetStringAsync("https://msdn.microsoft.com");

        // THREE                 
        string urlContents = await getStringTask;

        // FIVE
        return urlContents.Length;
    }
}

Ces emplacements étiquetés, « ONE » à « SIX, » affiche des informations sur l'état actuel du programme.La sortie suivante a été générée.

ONE:   Entering startButton_Click.
           Calling AccessTheWebAsync.

TWO:   Entering AccessTheWebAsync.
           Calling HttpClient.GetStringAsync.

THREE: Back in AccessTheWebAsync.
           Task getStringTask is started.
           About to await getStringTask & return a Task<int> to startButton_Click.

FOUR:  Back in startButton_Click.
           Task getLengthTask is started.
           About to await getLengthTask -- no caller to return to.

FIVE:  Back in AccessTheWebAsync.
           Task getStringTask is complete.
           Processing the return statement.
           Exiting from AccessTheWebAsync.

SIX:   Back in startButton_Click.
           Task getLengthTask is finished.
           Result from AccessTheWebAsync is stored in contentLength.
           About to display contentLength and exit.

Length of the downloaded string: 33946.

Configurez le programme.

Vous pouvez télécharger le code que cette rubrique utilise sur MSDN, ou vous pouvez le créer vous-même.

[!REMARQUE]

Pour exécuter l'exemple, vous devez avoir installé Visual Studio 2012, Visual Studio express 2012, ou .NET Framework 4,5 sur votre ordinateur.

Hh873191.collapse_all(fr-fr,VS.110).gifTéléchargez le programme

Vous pouvez télécharger l'application de cette rubrique sur Exemple Async : Flux de contrôle dans les programmes AsyncLes étapes suivantes ouvrent et activent le programme.

  1. Décompressez le fichier téléchargé, puis démarrez Visual Studio 2012.

  2. Dans la barre de menus, sélectionnez Fichier, Ouvrir, Projet/Solution.

  3. Accédez au dossier qui contient l'exemple de code dézippé, ouvrez le fichier solution (.sln), puis choisissez la touche F5 pour générer et exécuter le projet.

Hh873191.collapse_all(fr-fr,VS.110).gifGénérez le programme vous-même

Le projet Windows Presentation Foundation (WPF) suivant contient les exemples de code pour cette rubrique.

Pour exécuter le projet , exécutez les étapes suivantes :

  1. Démarrez Visual Studio.

  2. Dans la barre de menus, sélectionnez Fichier, Nouveau, Project.

    La boîte de dialogue Nouveau projet s'affiche.

  3. Dans le volet Modèles installés , choisissez Visual Basic ou Visual C#, puis choisissez Application WPF dans la liste des types de projets.

  4. Entrez AsyncTracer comme nom du projet, puis cliquez sur OK .

    Le nouveau projet s'affiche dans l'Explorateur de solutions.

  5. Dans l'éditeur de code Visual Studio, choisissez l'onglet MainWindow.xaml.

    Si l'onglet n'est pas visible, ouvrez le menu contextuel de MainWindow.xaml dans Explorateur de solutions, puis choisissez Afficher le code.

  6. dans la vue XAML de MainWindow.xaml, remplacez le code par le code suivant.

    <Window
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow"
        Title="Control Flow Trace" Height="350" Width="525">
        <Grid>
            <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top" Width="75"/>
            <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="510" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" d:LayoutOverrides="HorizontalMargin"/>
    
        </Grid>
    </Window>
    
    <Window
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="AsyncTracer.MainWindow"
            Title="Control Flow Trace" Height="350" Width="592">
        <Grid>
            <Button x:Name="startButton" Content="Start&#xa;" HorizontalAlignment="Left" Margin="250,10,0,0" VerticalAlignment="Top" Width="75" Height="24"  Click="startButton_Click" d:LayoutOverrides="GridBox"/>
            <TextBox x:Name="resultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="576" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" Grid.ColumnSpan="3"/>
        </Grid>
    </Window>
    

    Une fenêtre simple qui contient une TextBox et un bouton apparaît dans la vue Design de MainWindow.xaml.

  7. Ajouter la référence System.Net.Http.

  8. Dans L'Explorateur de solutions, ouvrez le menu contextuel pour MainWindow.xaml.vb ou MainWindow.xaml.cs puis choisissez Afficher le Code.

  9. Dans MainWindow.xaml.vb or MainWindow.xaml.cs, remplacez le code par le code suivant.

    ' Add an Imports statement and a reference for System.Net.Http.
    Imports System.Net.Http
    
    Class MainWindow
    
        Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
    
            ' The display lines in the example lead you through the control shifts.
            ResultsTextBox.Text &= "ONE:   Entering StartButton_Click." & vbCrLf &
                "           Calling AccessTheWebAsync." & vbCrLf
    
            Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
    
            ResultsTextBox.Text &= vbCrLf & "FOUR:  Back in StartButton_Click." & vbCrLf &
                "           Task getLengthTask is started." & vbCrLf &
                "           About to await getLengthTask -- no caller to return to." & vbCrLf
    
            Dim contentLength As Integer = Await getLengthTask
    
            ResultsTextBox.Text &= vbCrLf & "SIX:   Back in StartButton_Click." & vbCrLf &
                "           Task getLengthTask is finished." & vbCrLf &
                "           Result from AccessTheWebAsync is stored in contentLength." & vbCrLf &
                "           About to display contentLength and exit." & vbCrLf
    
            ResultsTextBox.Text &=
                String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)
        End Sub
    
    
        Async Function AccessTheWebAsync() As Task(Of Integer)
    
            ResultsTextBox.Text &= vbCrLf & "TWO:   Entering AccessTheWebAsync."
    
            ' Declare an HttpClient object.
            Dim client As HttpClient = New HttpClient()
    
            ResultsTextBox.Text &= vbCrLf & "           Calling HttpClient.GetStringAsync." & vbCrLf
    
            ' GetStringAsync returns a Task(Of String). 
            Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")
    
            ResultsTextBox.Text &= vbCrLf & "THREE: Back in AccessTheWebAsync." & vbCrLf &
                "           Task getStringTask is started."
    
            ' AccessTheWebAsync can continue to work until getStringTask is awaited.
    
            ResultsTextBox.Text &=
                vbCrLf & "           About to await getStringTask & return a Task(Of Integer) to StartButton_Click." & vbCrLf
    
            ' Retrieve the website contents when task is complete.
            Dim urlContents As String = Await getStringTask
    
            ResultsTextBox.Text &= vbCrLf & "FIVE:  Back in AccessTheWebAsync." &
                vbCrLf & "           Task getStringTask is complete." &
                vbCrLf & "           Processing the return statement." &
                vbCrLf & "           Exiting from AccessTheWebAsync." & vbCrLf
    
            Return urlContents.Length
        End Function
    
    End Class
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    // Add a using directive and a reference for System.Net.Http;
    using System.Net.Http;
    
    namespace AsyncTracer
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private async void startButton_Click(object sender, RoutedEventArgs e)
            {
                // The display lines in the example lead you through the control shifts.
                resultsTextBox.Text += "ONE:   Entering startButton_Click.\r\n" +
                    "           Calling AccessTheWebAsync.\r\n";
    
                Task<int> getLengthTask = AccessTheWebAsync();
    
                resultsTextBox.Text += "\r\nFOUR:  Back in startButton_Click.\r\n" +
                    "           Task getLengthTask is started.\r\n" +
                    "           About to await getLengthTask -- no caller to return to.\r\n";
    
                int contentLength = await getLengthTask;
    
                resultsTextBox.Text += "\r\nSIX:   Back in startButton_Click.\r\n" +
                    "           Task getLengthTask is finished.\r\n" +
                    "           Result from AccessTheWebAsync is stored in contentLength.\r\n" +
                    "           About to display contentLength and exit.\r\n";
    
                resultsTextBox.Text +=
                    String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
            }
    
    
            async Task<int> AccessTheWebAsync()
            {
                resultsTextBox.Text += "\r\nTWO:   Entering AccessTheWebAsync.";
    
                // Declare an HttpClient object.
                HttpClient client = new HttpClient();
    
                resultsTextBox.Text += "\r\n           Calling HttpClient.GetStringAsync.\r\n";
    
                // GetStringAsync returns a Task<string>. 
                Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");
    
                resultsTextBox.Text += "\r\nTHREE: Back in AccessTheWebAsync.\r\n" +
                    "           Task getStringTask is started.";
    
                // AccessTheWebAsync can continue to work until getStringTask is awaited.
    
                resultsTextBox.Text +=
                    "\r\n           About to await getStringTask and return a Task<int> to startButton_Click.\r\n";
    
                // Retrieve the website contents when task is complete.
                string urlContents = await getStringTask;
    
                resultsTextBox.Text += "\r\nFIVE:  Back in AccessTheWebAsync." +
                    "\r\n           Task getStringTask is complete." +
                    "\r\n           Processing the return statement." +
                    "\r\n           Exiting from AccessTheWebAsync.\r\n";
    
                return urlContents.Length;
            }
        }
    }
    
  10. Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer .

    La sortie suivante doit apparaître.

    ONE:   Entering startButton_Click.
               Calling AccessTheWebAsync.
    
    TWO:   Entering AccessTheWebAsync.
               Calling HttpClient.GetStringAsync.
    
    THREE: Back in AccessTheWebAsync.
               Task getStringTask is started.
               About to await getStringTask & return a Task<int> to startButton_Click.
    
    FOUR:  Back in startButton_Click.
               Task getLengthTask is started.
               About to await getLengthTask -- no caller to return to.
    
    FIVE:  Back in AccessTheWebAsync.
               Task getStringTask is complete.
               Processing the return statement.
               Exiting from AccessTheWebAsync.
    
    SIX:   Back in startButton_Click.
               Task getLengthTask is finished.
               Result from AccessTheWebAsync is stored in contentLength.
               About to display contentLength and exit.
    
    Length of the downloaded string: 33946.
    

Tracez le programme

Hh873191.collapse_all(fr-fr,VS.110).gifÉtapes UN et DEUX

Les deux premières lignes d'affichage suivent le chemin d'accès avec startButton_Clickqui appelle AccessTheWebAsync, et AccessTheWebAsync appelle la méthode asynchrone HttpClientGetStringAsync(String).L'image suivante montre les appels de méthode à méthode.

Étapes UN et DEUX

Le type de retour de AccessTheWebAsync et de client.GetStringAsync est Task<TResult>.Pour AccessTheWebAsync, TResult est un entier.Pour GetStringAsync, TResult est une chaîne.Pour plus d'informations sur les types de retour des méthodes async, consultez Types de retour Async (C# et Visual Basic).

Une méthode async retournant une tâche retourne une instance de tâche lorsque le contrôle se déplace vers l'appelant.Le contrôle retourne d´une méthode async à son appelant lorsqu'un opérateur Await ou await est produit dans la méthode appelée ou lorsque la méthode appelée se termine.Les lignes d'affichage qui sont étiquetées « THREE » à « SIX » traces cette partie du processus.

Hh873191.collapse_all(fr-fr,VS.110).gifÉtape TROIS

Dans AccessTheWebAsync, la méthode asynchrone GetStringAsync(String) est appelée pour télécharger le contenu de la page Web cible.Le contrôle retourne de client.GetStringAsync à AccessTheWebAsync lorsque client.GetStringAsync retourne.

La méthode client.GetStringAsync retourne une tâche de la chaîne assignée à la variable getStringTask dans AccessTheWebAsync.La ligne suivante dans le programme d'exemple illustre l'appel à client.GetStringAsync et l´assignation.

Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");

Vous pouvez considérer la tâche comme une promesse faite par client.GetStringAsync de produire une chaîne réelle par la suite.Dans le même temps, si AccessTheWebAsync a du travail à effectuer qui ne dépend pas de la chaîne promise de client.GetStringAsync, ce travail peut se poursuivre tant que client.GetStringAsync attend.Dans l'exemple, les lignes de sortie, qui sont étiquetées « THREE, » représentent la possibilité d'effectuer le travail indépendant

THREE: Back in AccessTheWebAsync.
           Task getStringTask is started.
           About to await getStringTask & return a Task<int> to startButton_Click.

L'instruction suivante interrompt la progression dans AccessTheWebAsync lorsque getStringTask est attendu.

Dim urlContents As String = Await getStringTask
string urlContents = await getStringTask;

L'image suivante montre l'ordre d'exécution de client.GetStringAsync au assignation à getStringTask et de création de getStringTask à la demande d'un opérateur d'attente.

Étape TROIS

L'expression d'attente interrompt AccessTheWebAsync jusqu'à ce que client.GetStringAsync retourne.Dans le même temps, le contrôle retourne à l'appelant de AccessTheWebAsync, startButton_Click.

[!REMARQUE]

En général, vous attendez l'appel à une méthode asynchrone immédiatement.Par exemple, l'une des assignations suivantes peut substituer le code précédent qui crée puis attend getStringTask:

  • Visual Basic : Dim urlContents As String = Await client.GetStringAsync("https://msdn.microsoft.com")

  • C#: string urlContents = await client.GetStringAsync("https://msdn.microsoft.com");

Dans cette rubrique, l'opérateur d'attente est appliqué ultérieurement pour s'adapter aux lignes de sortie qui marquent l'ordre d'exécution du programme.

Hh873191.collapse_all(fr-fr,VS.110).gifÉtape QUATRE

Le type de retour déclaré de AccessTheWebAsync est Task(Of Integer) en Visual Basic et Task<int> en C#.Par conséquent, lorsque AccessTheWebAsync est interrompu, il retourne une tâche d'entier à startButton_Click.Vous devez comprendre que la tâche retournée n'est pas getStringTask.La tâche retournée est une tâche de l'entier qui représente le reste à effectuer dans la méthode interrompue, AccessTheWebAsync.La tâche est une promesse de AccessTheWebAsync de produire un entier lorsque la tâche est terminée.

L'instruction suivante assigne cette tâche à la variable de getLengthTask .

Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Task<int> getLengthTask = AccessTheWebAsync();

Comme dans AccessTheWebAsync, startButton_Click peut continuer le travail qui ne dépend pas des résultats de la tâche asynchrone (getLengthTask) jusqu'à ce que la tâche soit attendue.Les lignes de sortie suivantes représentent ce travail.

FOUR:  Back in startButton_Click.
           Task getLengthTask is started.
           About to await getLengthTask -- no caller to return to.

La progression dans startButton_Click est interrompue lorsque getLengthTask est attendu.L'instruction d'assignation suivante interrompt startButton_Click jusqu'à ce que AccessTheWebAsync soit terminé.

Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;

Dans l'illustration suivante, les flèches indiquent l'ordre d'exécution de l'expression d'attente dans AccessTheWebAsync à l'assignation d'une valeur à getLengthTask, suivie du traitement normal dans startButton_Click jusqu'à ce que getLengthTask est attendu.

Étape QUATRE

Hh873191.collapse_all(fr-fr,VS.110).gifÉtape CINQ

Lorsque client.GetStringAsync signale qu'il est terminé, le traitement de AccessTheWebAsync est récupéré de la suspension et peut continuer après l'instruction d'attente.Les lignes de sortie représentent la récupération de traitement.

FIVE:  Back in AccessTheWebAsync.
           Task getStringTask is complete.
           Processing the return statement.
           Exiting from AccessTheWebAsync.

L'opérande de l'instruction return, urlContents.Length, est stocké dans la tâche que AccessTheWebAsync retourne.L'expression d'attente extrait la valeur de getLengthTask dans startButton_Click.

L'image suivante montre le transfert du contrôle après que client.GetStringAsync (et getStringTask) sont complètes.

Étape CINQ

AccessTheWebAsync s'exécute jusqu´à la fin, et le contrôle retourne à startButton_Click, qui attend la fin.

Hh873191.collapse_all(fr-fr,VS.110).gifÉtape SIX

Lorsque AccessTheWebAsync signale qu'il est terminé, le traitement peut continuer après l'instruction d'attente dans startButton_Async.En fait, le programme n'a rien à faire de plus.

Les lignes de sortie suivantes représentent la récupération de traitement dans startButton_Async.

SIX:   Back in startButton_Click.
           Task getLengthTask is finished.
           Result from AccessTheWebAsync is stored in contentLength.
           About to display contentLength and exit.

L'expression d'attente récupère de getLengthTask la valeur entière qui est l'opérande de l'instruction return dans AccessTheWebAsync.L'instruction suivante assigne la valeur à la variable contentLength .

Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;

L'image suivante montre le retour du contrôle de AccessTheWebAsync à startButton_Click.

Étape SIX

Voir aussi

Tâches

Procédure pas à pas : accès au Web avec Async et Await (C# et Visual Basic)

Procédure pas à pas : utilisation du débogueur avec les méthodes Async

Concepts

Programmation asynchrone avec Async et Await (C# et Visual Basic)

Types de retour Async (C# et Visual Basic)

Autres ressources

Exemple Async : Flux de contrôle dans les programmes Async (C# et Visual Basic)