Comment : effectuer plusieurs requêtes Web en parallèle en utilisant Async et Await (C# et Visual Basic)

Dans une méthode asynchrone, les tâches sont démarrées lorsqu'elles sont créées. L'opérateur Await (Visual Basic) ou await (C#) est appliqué à la tâche au point de la méthode où le traitement ne peut pas continuer jusqu'à ce que la tâche se termine. Souvent, une tâche est attendue dès qu'elle est créé, comme le montre l'exemple suivant.

Dim result = Await someWebAccessMethodAsync(url)
var result = await someWebAccessMethodAsync(url);

Cependant, vous pouvez séparer la création et l'attente de la tâche si votre programme a un autre travail à accomplir qui ne dépend pas de l'achèvement de la tâche.

' The following line creates and starts the task.
Dim myTask = someWebAccessMethodAsync(url)

' While the task is running, you can do other work that does not depend
' on the results of the task.
' . . . . .

' The application of Await suspends the rest of this method until the task is 
' complete.
Dim result = Await myTask
// The following line creates and starts the task.
var myTask = someWebAccessMethodAsync(url);

// While the task is running, you can do other work that doesn't depend
// on the results of the task.
// . . . . .

// The application of await suspends the rest of this method until the task is complete.
var result = await myTask;

Entre le lancement d'une tâche et son attente, vous pouvez démarrer d'autres tâches. Les tâches supplémentaires sont implicitement exécutées en parallèle, mais aucun thread supplémentaire n'est créé.

Le programme suivant démarre trois téléchargements web asynchrones et les attend ensuite dans l'ordre dans lequel ils sont appelés. Notez, lorsque vous exécutez le programme, que les tâches ne se terminent pas toujours dans l'ordre dans lequel elles sont créées et attendues. Elles commencent à s'exécuter lorsqu'elles sont créées, et une ou plusieurs tâches peuvent se terminer avant que la méthode atteigne les expressions await.

Notes

Pour terminer ce projet, Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 pour Windows Desktop, Visual Studio Express 2013 pour Windows ou le .NET Framework 4.5 ou 4.5.1 doit être installé sur votre ordinateur.

Pour un autre exemple qui démarre plusieurs tâches en même temps, voir Comment : étendre la procédure pas à pas Async à l'aide de Task.WhenAll (C# et Visual Basic).

Vous pouvez télécharger le code pour cet exemple depuis Exemples de code du développeur.

Pour configurer le projet

  • Pour configurer une application WPF, procédez comme suit. Vous pouvez trouver des instructions détaillées pour ces étapes dans Procédure pas à pas : accès au Web avec Async et Await (C# et Visual Basic).

    • Créer une application WPF qui contient une zone de texte et un bouton. Nommez le bouton startButton et nommez la zone de texte resultsTextBox.

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

    • Dans MainWindow.xaml.vb ou MainWindow.xaml.cs, ajoutez une instruction Imports ou une directive using pour System.Net.Http.

Pour ajouter le code

  1. Dans la fenêtre de conception, MainWindow.xaml, double-cliquez sur le bouton pour créer le gestionnaire d'évènements startButton_Click dans MainWindow.xaml.vb ou MainWindow.xaml.cs. Comme alternative, sélectionnez le bouton, sélectionnez l'icône Gestionnaires d'événements pour les éléments sélectionnés de la fenêtre Propriétés, puis entrez startButton_Click dans la zone de texte Cliquer.

  2. Copiez le code suivant et collez-le dans le corps de startButton_Click dans MainWindow.xaml.vb ou MainWindow.xaml.cs.

    resultsTextBox.Clear()
    Await CreateMultipleTasksAsync()
    resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    
    resultsTextBox.Clear();
    await CreateMultipleTasksAsync();
    resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
    

    Le code appelle une méthode asynchrone, CreateMultipleTasksAsync, qui pilote l'application.

  3. Ajoutez les méthodes de support suivantes au projet :

    • ProcessURLAsync utilise une méthode HttpClient pour télécharger le contenu d'un site Web en tant que tableau d'octets. La méthode de support, ProcessURLAsync affiche et retourne la longueur du tableau.

    • DisplayResults affiche le nombre d'octets dans le tableau d'octets de chaque URL. Cet affichage apparaît lorsque chaque tâche a fini d'être téléchargée.

    Copiez les méthodes suivantes, puis collez-les après le gestionnaire d'événements startButton_Click dans MainWindow.xaml.vb ou MainWindow.xaml.cs.

    Private Async Function ProcessURLAsync(url As String, client As HttpClient) As Task(Of Integer)
    
        Dim byteArray = Await client.GetByteArrayAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function 
    
    
    Private Sub DisplayResults(url As String, content As Byte())
    
        ' Display the length of each website. The string format  
        ' is designed to be used with a monospaced font, such as 
        ' Lucida Console or Global Monospace. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub
    
    async Task<int> ProcessURLAsync(string url, HttpClient client)
    {
        var byteArray = await client.GetByteArrayAsync(url);
        DisplayResults(url, byteArray);
        return byteArray.Length;
    }
    
    
    private void DisplayResults(string url, byte[] content)
    {
        // Display the length of each website. The string format  
        // is designed to be used with a monospaced font, such as 
        // Lucida Console or Global Monospace. 
        var bytes = content.Length;
        // Strip off the "http://".
        var displayURL = url.Replace("http://", "");
        resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
    }
    
  4. Pour finir, définissez la méthode CreateMultipleTasksAsync, qui effectue les étapes suivantes.

    • La méthode déclare un objet HttpClient dont vous avez besoin pour accéder à la méthode GetByteArrayAsync dans ProcessURLAsync.

    • La méthode crée et démarre trois tâches de type Task, où TResult est un entier. Chaque fois qu'une tâche se termine, DisplayResults affiche l'URL de la tâche et la longueur du contenu téléchargé. Comme les tâches s'exécutent de manière asynchrone, l'ordre dans lequel les résultats s'affichent peut être différent de l'ordre dans lequel elles ont été déclarées.

    • La méthode attend la fin de chaque tâche. Chaque opérateur Await ou await interrompt l'exécution de CreateMultipleTasksAsync jusqu'à ce que la tâche attendue soit terminée. L'opérateur extrait également la valeur de retour de l'appel à ProcessURLAsync à partir de chaque tâche achevée.

    • Lorsque les tâches ont été effectuées et que les valeurs entières ont été récupérées, la méthode ajoute les longueurs des sites Web et affiche le résultat.

    Copiez la méthode suivante et collez-la dans votre solution.

    Private Async Function CreateMultipleTasksAsync() As Task
    
        ' Declare an HttpClient object, and increase the buffer size. The 
        ' default buffer size is 65,536. 
        Dim client As HttpClient =
            New HttpClient() With {.MaxResponseContentBufferSize = 1000000}
    
        ' Create and start the tasks. As each task finishes, DisplayResults  
        ' displays its length. 
        Dim download1 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com", client)
        Dim download2 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client)
        Dim download3 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client)
    
        ' Await each task. 
        Dim length1 As Integer = Await download1
        Dim length2 As Integer = Await download2
        Dim length3 As Integer = Await download3
    
        Dim total As Integer = length1 + length2 + length3
    
        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function
    
    private async Task CreateMultipleTasksAsync()
    {
        // Declare an HttpClient object, and increase the buffer size. The 
        // default buffer size is 65,536.
        HttpClient client =
            new HttpClient() { MaxResponseContentBufferSize = 1000000 };
    
        // Create and start the tasks. As each task finishes, DisplayResults  
        // displays its length.
        Task<int> download1 = 
            ProcessURLAsync("https://msdn.microsoft.com", client);
        Task<int> download2 = 
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client);
        Task<int> download3 = 
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client);
    
        // Await each task. 
        int length1 = await download1;
        int length2 = await download2;
        int length3 = await download3;
    
        int total = length1 + length2 + length3;
    
        // Display the total count for the downloaded websites.
        resultsTextBox.Text +=
            string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
    }
    
  5. Choisissez la touche F5 pour exécuter le programme, puis choisissez le bouton Démarrer.

    Exécutez le programme plusieurs fois pour vérifier que les trois tâches ne se terminent pas toujours dans le même ordre et que l'ordre dans lequel elles se terminent n'est pas nécessairement l'ordre dans lequel elles sont créés et attendues.

Exemple

Le code suivant inclut l'exemple complet.

' Add the following Imports statements, and add a reference for System.Net.Http. 
Imports System.Net.Http


Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click
        resultsTextBox.Clear()
        Await CreateMultipleTasksAsync()
        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click." 
    End Sub 


    Private Async Function CreateMultipleTasksAsync() As Task

        ' Declare an HttpClient object, and increase the buffer size. The 
        ' default buffer size is 65,536. 
        Dim client As HttpClient =
            New HttpClient() With {.MaxResponseContentBufferSize = 1000000}

        ' Create and start the tasks. As each task finishes, DisplayResults  
        ' displays its length. 
        Dim download1 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com", client)
        Dim download2 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client)
        Dim download3 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client)

        ' Await each task. 
        Dim length1 As Integer = Await download1
        Dim length2 As Integer = Await download2
        Dim length3 As Integer = Await download3

        Dim total As Integer = length1 + length2 + length3

        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function 


    Private Async Function ProcessURLAsync(url As String, client As HttpClient) As Task(Of Integer)

        Dim byteArray = Await client.GetByteArrayAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function 


    Private Sub DisplayResults(url As String, content As Byte())

        ' Display the length of each website. The string format  
        ' is designed to be used with a monospaced font, such as 
        ' Lucida Console or Global Monospace. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub 
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 the following using directive, and add a reference for System.Net.Http. 
using System.Net.Http;


namespace AsyncExample_MultipleTasks
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();
            await CreateMultipleTasksAsync();
            resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
        }


        private async Task CreateMultipleTasksAsync()
        {
            // Declare an HttpClient object, and increase the buffer size. The 
            // default buffer size is 65,536.
            HttpClient client =
                new HttpClient() { MaxResponseContentBufferSize = 1000000 };

            // Create and start the tasks. As each task finishes, DisplayResults  
            // displays its length.
            Task<int> download1 = 
                ProcessURLAsync("https://msdn.microsoft.com", client);
            Task<int> download2 = 
                ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client);
            Task<int> download3 = 
                ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client);

            // Await each task. 
            int length1 = await download1;
            int length2 = await download2;
            int length3 = await download3;

            int total = length1 + length2 + length3;

            // Display the total count for the downloaded websites.
            resultsTextBox.Text +=
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
        }


        async Task<int> ProcessURLAsync(string url, HttpClient client)
        {
            var byteArray = await client.GetByteArrayAsync(url);
            DisplayResults(url, byteArray);
            return byteArray.Length;
        }


        private void DisplayResults(string url, byte[] content)
        {
            // Display the length of each website. The string format  
            // is designed to be used with a monospaced font, such as 
            // Lucida Console or Global Monospace. 
            var bytes = content.Length;
            // Strip off the "http://".
            var displayURL = url.Replace("http://", "");
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
        }
    }
}

Voir aussi

Tâches

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

Comment : étendre la procédure pas à pas Async à l'aide de Task.WhenAll (C# et Visual Basic)

Concepts

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