Procédure : Étendre la procédure pas à pas Async à l’aide de Task. WhenAll (Visual Basic)How to: Extend the Async Walkthrough by Using Task.WhenAll (Visual Basic)

Vous pouvez améliorer les performances de la solution async dans Procédure pas à pas : Accès au Web avec Async et await (Visual Basic) à l’aide de la Task.WhenAll méthode.You can improve the performance of the async solution in Walkthrough: Accessing the Web by Using Async and Await (Visual Basic) by using the Task.WhenAll method. Cette méthode attend de manière asynchrone plusieurs opérations, qui sont représentées sous la forme d’une collection de tâches.This method asynchronously awaits multiple asynchronous operations, which are represented as a collection of tasks.

Vous aurez peut-être remarqué dans la procédure pas à pas que les sites web se téléchargent à différentes vitesses.You might have noticed in the walkthrough that the websites download at different rates. L’un des sites web est parfois très lent, ce qui retarde tous les autres téléchargements.Sometimes one of the websites is very slow, which delays all the remaining downloads. Quand vous exécutez les solutions asynchrones que vous générez dans la procédure pas à pas, vous pouvez quitter le programme facilement si vous ne souhaitez pas attendre, mais une meilleure option consiste à démarrer tous les téléchargements en même temps et à laisser les plus rapides se poursuivre sans attendre celui qui est retardé.When you run the asynchronous solutions that you build in the walkthrough, you can end the program easily if you don't want to wait, but a better option would be to start all the downloads at the same time and let faster downloads continue without waiting for the one that’s delayed.

Vous appliquez la méthode Task.WhenAll à une collection de tâches.You apply the Task.WhenAll method to a collection of tasks. L’application de WhenAll retourne une tâche unique qui n’est pas terminée tant que toutes les tâches de la collection ne sont pas terminées.The application of WhenAll returns a single task that isn’t complete until every task in the collection is completed. Les tâches s’exécutent en parallèle, mais aucun thread supplémentaire n’est créé.The tasks appear to run in parallel, but no additional threads are created. Les tâches peuvent se terminer dans n’importe quel ordre.The tasks can complete in any order.

Important

Les procédures suivantes décrivent des extensions pour les applications asynchrones qui sont développées dans Procédure pas à pas : Accès au Web avec Async et await (Visual Basic).The following procedures describe extensions to the async applications that are developed in Walkthrough: Accessing the Web by Using Async and Await (Visual Basic). Vous pouvez développer les applications soit en appliquant la procédure pas à pas, soit en téléchargeant le code à partir des Exemples de code du développeur.You can develop the applications by either completing the walkthrough or downloading the code from Developer Code Samples.

Pour exécuter l’exemple, Visual Studio 2012 ou version ultérieure doit être installé sur votre ordinateur.To run the example, you must have Visual Studio 2012 or later installed on your computer.

Pour ajouter Task.WhenAll à votre solution GetURLContentsAsyncTo add Task.WhenAll to your GetURLContentsAsync solution

  1. Ajoutez la méthode ProcessURLAsync à la première application développée dans Procédure pas à pas : Accès au Web avec Async et await (Visual Basic).Add the ProcessURLAsync method to the first application that's developed in Walkthrough: Accessing the Web by Using Async and Await (Visual Basic).

    • Si vous avez téléchargé le code à partir des exemples de code du développeur, ouvrez le projet ProcessURLAsync AsyncWalkthrough, puis ajoutez-le au fichier MainWindow. Xaml. vb.If you downloaded the code from Developer Code Samples, open the AsyncWalkthrough project, and then add ProcessURLAsync to the MainWindow.xaml.vb file.

    • Si vous avez développé le code en appliquant la procédure pas à pas, ajoutez ProcessURLAsync à l’application qui inclut la méthode GetURLContentsAsync.If you developed the code by completing the walkthrough, add ProcessURLAsync to the application that includes the GetURLContentsAsync method. Le fichier MainWindow. Xaml. vb pour cette application est le premier exemple de la section «Exemples de code complets de la procédure pas à pas».The MainWindow.xaml.vb file for this application is the first example in the "Complete Code Examples from the Walkthrough" section.

    La méthode ProcessURLAsync consolide les actions dans le corps de la boucle For Each dans SumPageSizesAsync dans la procédure d’origine.The ProcessURLAsync method consolidates the actions in the body of the For Each loop in SumPageSizesAsync in the original walkthrough. La méthode télécharge de façon asynchrone le contenu d’un site web spécifié sous forme de tableau d’octets, puis affiche et retourne la longueur du tableau d’octets.The method asynchronously downloads the contents of a specified website as a byte array, and then displays and returns the length of the byte array.

    Private Async Function ProcessURLAsync(url As String) As Task(Of Integer)  
    
        Dim byteArray = Await GetURLContentsAsync(url)  
        DisplayResults(url, byteArray)  
        Return byteArray.Length  
    End Function  
    
  2. Commentez ou supprimez la boucle For Each dans SumPageSizesAsync, comme illustré dans le code suivant.Comment out or delete the For Each loop in SumPageSizesAsync, as the following code shows.

    'Dim total = 0  
    'For Each url In urlList  
    
    '    Dim urlContents As Byte() = Await GetURLContentsAsync(url)  
    
    '    ' The previous line abbreviates the following two assignment statements.  
    
    '    ' GetURLContentsAsync returns a task. At completion, the task  
    '    ' produces a byte array.  
    '    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url)  
    '    'Dim urlContents As Byte() = Await getContentsTask  
    
    '    DisplayResults(url, urlContents)  
    
    '    ' Update the total.  
    '    total += urlContents.Length  
    'Next  
    
  3. Créez une collection de tâches.Create a collection of tasks. Le code suivant définit une requête qui, quand elle est exécutée par la méthode ToArray, crée une collection de tâches qui téléchargent le contenu de chaque site web.The following code defines a query that, when executed by the ToArray method, creates a collection of tasks that download the contents of each website. Les tâches sont démarrées quand la requête est évaluée.The tasks are started when the query is evaluated.

    Ajoutez le code suivant à la méthode SumPageSizesAsync après la déclaration de urlList.Add the following code to method SumPageSizesAsync after the declaration of urlList.

    ' Create a query.   
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
        From url In urlList Select ProcessURLAsync(url)  
    
    ' Use ToArray to execute the query and start the download tasks.  
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()  
    
  4. Appliquez Task.WhenAll à la collection de tâches, downloadTasks.Apply Task.WhenAll to the collection of tasks, downloadTasks. Task.WhenAll retourne une tâche unique qui se termine quand toutes les tâches de la collection de tâches sont terminées.Task.WhenAll returns a single task that finishes when all the tasks in the collection of tasks have completed.

    Dans l’exemple suivant, l’expression Await attend l’achèvement de la tâche unique retournée par WhenAll.In the following example, the Await expression awaits the completion of the single task that WhenAll returns. L’expression correspond à un tableau d’entiers, où chaque entier est la longueur d’un site web téléchargé.The expression evaluates to an array of integers, where each integer is the length of a downloaded website. Ajoutez le code suivant à SumPageSizesAsync, juste après le code ajouté à l’étape précédente.Add the following code to SumPageSizesAsync, just after the code that you added in the previous step.

    ' Await the completion of all the running tasks.  
    Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)  
    
    '' The previous line is equivalent to the following two statements.  
    'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)  
    'Dim lengths As Integer() = Await whenAllTask  
    
  5. Enfin, utilisez la méthode Sum pour calculer la somme des longueurs de tous les sites web.Finally, use the Sum method to calculate the sum of the lengths of all the websites. Ajoutez la ligne suivante à SumPageSizesAsync.Add the following line to SumPageSizesAsync.

    Dim total = lengths.Sum()  
    

Pour ajouter Task.WhenAll à la solution HttpClient.GetByteArrayAsyncTo add Task.WhenAll to the HttpClient.GetByteArrayAsync solution

  1. Ajoutez la version suivante de ProcessURLAsync à la deuxième application développée dans Procédure pas à pas : Accès au Web avec Async et await (Visual Basic).Add the following version of ProcessURLAsync to the second application that's developed in Walkthrough: Accessing the Web by Using Async and Await (Visual Basic).

    • Si vous avez téléchargé le code à partir des exemples de code du développeur, ouvrez le projet ProcessURLAsync AsyncWalkthrough_HttpClient, puis ajoutez-le au fichier MainWindow. Xaml. vb.If you downloaded the code from Developer Code Samples, open the AsyncWalkthrough_HttpClient project, and then add ProcessURLAsync to the MainWindow.xaml.vb file.

    • Si vous avez développé le code en appliquant la procédure pas à pas, ajoutez ProcessURLAsync à l’application qui utilise la méthode HttpClient.GetByteArrayAsync.If you developed the code by completing the walkthrough, add ProcessURLAsync to the application that uses the HttpClient.GetByteArrayAsync method. Le fichier MainWindow. Xaml. vb pour cette application est le deuxième exemple de la section «Exemples de code complets de la procédure pas à pas».The MainWindow.xaml.vb file for this application is the second example in the "Complete Code Examples from the Walkthrough" section.

    La méthode ProcessURLAsync consolide les actions dans le corps de la boucle For Each dans SumPageSizesAsync dans la procédure d’origine.The ProcessURLAsync method consolidates the actions in the body of the For Each loop in SumPageSizesAsync in the original walkthrough. La méthode télécharge de façon asynchrone le contenu d’un site web spécifié sous forme de tableau d’octets, puis affiche et retourne la longueur du tableau d’octets.The method asynchronously downloads the contents of a specified website as a byte array, and then displays and returns the length of the byte array.

    La seule différence par rapport à la méthode ProcessURLAsync de la procédure précédente est l’utilisation de l’instance HttpClient, client.The only difference from the ProcessURLAsync method in the previous procedure is the use of the HttpClient instance, client.

    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  
    
  2. Commentez ou supprimez la boucle For Each dans SumPageSizesAsync, comme illustré dans le code suivant.Comment out or delete the For Each loop in SumPageSizesAsync, as the following code shows.

    'Dim total = 0   
    'For Each url In urlList   
    '    ' GetByteArrayAsync returns a task. At completion, the task   
    '    ' produces a byte array.   
    '    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)   
    
    '    ' The following two lines can replace the previous assignment statement.   
    '    'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url)   
    '    'Dim urlContents As Byte() = Await getContentsTask   
    
    '    DisplayResults(url, urlContents)   
    
    '    ' Update the total.   
    '    total += urlContents.Length   
    'Next  
    
  3. Définissez une requête qui, quand elle est exécutée par la méthode ToArray, crée une collection de tâches qui téléchargent le contenu de chaque site web.Define a query that, when executed by the ToArray method, creates a collection of tasks that download the contents of each website. Les tâches sont démarrées quand la requête est évaluée.The tasks are started when the query is evaluated.

    Ajoutez le code suivant à la méthode SumPageSizesAsync après la déclaration de client et urlList.Add the following code to method SumPageSizesAsync after the declaration of client and urlList.

    ' Create a query.  
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
        From url In urlList Select ProcessURLAsync(url, client)  
    
    ' Use ToArray to execute the query and start the download tasks.  
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()  
    
  4. Ensuite, appliquez Task.WhenAll à la collection de tâches, downloadTasks.Next, apply Task.WhenAll to the collection of tasks, downloadTasks. Task.WhenAll retourne une tâche unique qui se termine quand toutes les tâches de la collection de tâches sont terminées.Task.WhenAll returns a single task that finishes when all the tasks in the collection of tasks have completed.

    Dans l’exemple suivant, l’expression Await attend l’achèvement de la tâche unique retournée par WhenAll.In the following example, the Await expression awaits the completion of the single task that WhenAll returns. Une fois cette tâche achevée, l’expression Await correspond à un tableau d’entiers, où chaque entier est la longueur d’un site web téléchargé.When complete, the Await expression evaluates to an array of integers, where each integer is the length of a downloaded website. Ajoutez le code suivant à SumPageSizesAsync, juste après le code ajouté à l’étape précédente.Add the following code to SumPageSizesAsync, just after the code that you added in the previous step.

    ' Await the completion of all the running tasks.  
    Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)  
    
    '' The previous line is equivalent to the following two statements.  
    'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)  
    'Dim lengths As Integer() = Await whenAllTask  
    
  5. Enfin, utilisez la méthode Sum pour obtenir la somme des longueurs de tous les sites web.Finally, use the Sum method to get the sum of the lengths of all the websites. Ajoutez la ligne suivante à SumPageSizesAsync.Add the following line to SumPageSizesAsync.

    Dim total = lengths.Sum()  
    

Pour tester les solutions Task.WhenAllTo test the Task.WhenAll solutions

ExempleExample

Le code suivant montre les extensions du projet qui utilise la méthode GetURLContentsAsync pour télécharger du contenu à partir du web.The following code shows the extensions to the project that uses the GetURLContentsAsync method to download content from the web.

' Add the following Imports statements, and add a reference for System.Net.Http.  
Imports System.Net.Http  
Imports System.Net  
Imports System.IO  
  
Class MainWindow  
  
    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click  
  
        resultsTextBox.Clear()  
  
        ' One-step async call.  
        Await SumPageSizesAsync()  
  
        '' Two-step async call.  
        'Dim sumTask As Task = SumPageSizesAsync()  
        'Await sumTask  
  
        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."  
    End Sub  
  
    Private Async Function SumPageSizesAsync() As Task  
  
        ' Make a list of web addresses.  
        Dim urlList As List(Of String) = SetUpURLList()  
  
        ' Create a query.   
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
            From url In urlList Select ProcessURLAsync(url)  
  
        ' Use ToArray to execute the query and start the download tasks.  
        Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()  
  
        ' You can do other work here before awaiting.  
  
        ' Await the completion of all the running tasks.  
        Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)  
  
        '' The previous line is equivalent to the following two statements.  
        'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)  
        'Dim lengths As Integer() = Await whenAllTask  
  
        Dim total = lengths.Sum()  
  
        'Dim total = 0  
        'For Each url In urlList  
  
        '    Dim urlContents As Byte() = Await GetURLContentsAsync(url)  
  
        '    ' The previous line abbreviates the following two assignment statements.  
  
        '    ' GetURLContentsAsync returns a task. At completion, the task  
        '    ' produces a byte array.  
        '    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url)  
        '    'Dim urlContents As Byte() = Await getContentsTask  
  
        '    DisplayResults(url, urlContents)  
  
        '    ' Update the total.  
        '    total += urlContents.Length  
        'NextNext  
  
        ' Display the total count for all of the web addresses.  
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &  
                                             "Total bytes returned:  {0}" & vbCrLf, total)  
    End Function  
  
    Private Function SetUpURLList() As List(Of String)  
  
        Dim urls = New List(Of String) From  
            {  
                "https://msdn.microsoft.com",  
                "https://msdn.microsoft.com/library/hh290136.aspx",  
                "https://msdn.microsoft.com/library/ee256749.aspx",  
                "https://msdn.microsoft.com/library/hh290138.aspx",  
                "https://msdn.microsoft.com/library/hh290140.aspx",  
                "https://msdn.microsoft.com/library/dd470362.aspx",  
                "https://msdn.microsoft.com/library/aa578028.aspx",  
                "https://msdn.microsoft.com/library/ms404677.aspx",  
                "https://msdn.microsoft.com/library/ff730837.aspx"  
            }  
        Return urls  
    End Function  
  
    ' The actions from the foreach loop are moved to this async method.  
    Private Async Function ProcessURLAsync(url As String) As Task(Of Integer)  
  
        Dim byteArray = Await GetURLContentsAsync(url)  
        DisplayResults(url, byteArray)  
        Return byteArray.Length  
    End Function  
  
    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())  
  
        ' The downloaded resource ends up in the variable named content.  
        Dim content = New MemoryStream()  
  
        ' Initialize an HttpWebRequest for the current URL.  
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)  
  
        ' Send the request to the Internet resource and wait for  
        ' the response.  
        Using response As WebResponse = Await webReq.GetResponseAsync()  
            ' Get the data stream that is associated with the specified URL.  
            Using responseStream As Stream = response.GetResponseStream()  
                ' Read the bytes in responseStream and copy them to content.    
                ' CopyToAsync returns a Task, not a Task<T>.  
                Await responseStream.CopyToAsync(content)  
            End Using  
        End Using  
  
        ' Return the result as a byte array.  
        Return content.ToArray()  
    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 "https://".  
        Dim displayURL = url.Replace("https://", "")  
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)  
    End Sub  
  
End Class  

ExempleExample

Le code suivant montre les extensions du projet qui utilise la méthode HttpClient.GetByteArrayAsync pour télécharger du contenu à partir du web.The following code shows the extensions to the project that uses method HttpClient.GetByteArrayAsync to download content from the web.

' Add the following Imports statements, and add a reference for System.Net.Http.  
Imports System.Net.Http  
Imports System.Net  
Imports System.IO  
  
Class MainWindow  
  
    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click  
  
        resultsTextBox.Clear()  
  
        '' One-step async call.  
        Await SumPageSizesAsync()  
  
        '' Two-step async call.  
        'Dim sumTask As Task = SumPageSizesAsync()  
        'Await sumTask  
  
        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."  
    End Sub  
  
    Private Async Function SumPageSizesAsync() 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}  
  
        ' Make a list of web addresses.  
        Dim urlList As List(Of String) = SetUpURLList()  
  
        ' Create a query.  
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
            From url In urlList Select ProcessURLAsync(url, client)  
  
        ' Use ToArray to execute the query and start the download tasks.  
        Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()  
  
        ' You can do other work here before awaiting.  
  
        ' Await the completion of all the running tasks.  
        Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)  
  
        '' The previous line is equivalent to the following two statements.  
        'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)  
        'Dim lengths As Integer() = Await whenAllTask  
  
        Dim total = lengths.Sum()  
  
        ''<snippet7>  
        'Dim total = 0  
        'For Each url In urlList  
        '    ' GetByteArrayAsync returns a task. At completion, the task  
        '    ' produces a byte array.  
        '    '<snippet31>  
        '    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)  
        '    '</snippet31>  
  
        '    ' The following two lines can replace the previous assignment statement.  
        '    'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url)  
        '    'Dim urlContents As Byte() = Await getContentsTask  
  
        '    DisplayResults(url, urlContents)  
  
        '    ' Update the total.  
        '    total += urlContents.Length  
        'NextNext  
  
        ' Display the total count for all of the web addresses.  
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &  
                                             "Total bytes returned:  {0}" & vbCrLf, total)  
    End Function  
  
    Private Function SetUpURLList() As List(Of String)  
  
        Dim urls = New List(Of String) From  
            {  
                "https://www.msdn.com",  
                "https://msdn.microsoft.com/library/hh290136.aspx",  
                "https://msdn.microsoft.com/library/ee256749.aspx",  
                "https://msdn.microsoft.com/library/hh290138.aspx",  
                "https://msdn.microsoft.com/library/hh290140.aspx",  
                "https://msdn.microsoft.com/library/dd470362.aspx",  
                "https://msdn.microsoft.com/library/aa578028.aspx",  
                "https://msdn.microsoft.com/library/ms404677.aspx",  
                "https://msdn.microsoft.com/library/ff730837.aspx"  
            }  
        Return urls  
    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 "https://".  
        Dim displayURL = url.Replace("https://", "")  
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)  
    End Sub  
  
End Class  

Voir aussiSee also