Partager via


Démarrez plusieurs tâches asynchrones et traitez-les à mesure qu’elles se terminent (Visual Basic)

En utilisant Task.WhenAny, vous pouvez démarrer plusieurs tâches en même temps et les traiter une par une, au lieu de les traiter dans l’ordre dans lequel elles sont démarrées.

L’exemple suivant utilise une requête pour créer une collection de tâches. Chaque tâche télécharge le contenu d’un site web spécifié. À chaque itération d’une boucle while, un appel attendu à WhenAny retourne la tâche de la collection de tâches dont le téléchargement se termine en premier. Cette tâche est supprimée de la collection et traitée. La boucle se répète jusqu’à ce que la collection ne contienne plus de tâches.

Remarque

Pour exécuter les exemples, vous devez disposer de Visual Studio 2012 ou version ultérieure et du .NET Framework 4.5 ou ultérieur installé sur votre ordinateur.

Téléchargement de l’exemple

Vous pouvez télécharger le projet WPF (Windows Presentation Foundation) complet à partir de l’exemple Async : ajuster votre application , puis suivre ces étapes.

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

  2. Dans la barre de menus, choisissez Fichier, Ouvrir, Projet/Solution.

  3. Dans la boîte de dialogue Ouvrir un projet , ouvrez le dossier contenant l’exemple de code que vous avez décompressé, puis ouvrez le fichier de solution (.sln) pour AsyncFineTuningVB.

  4. Dans l’Explorateur de solutions, ouvrez le menu contextuel du projet ProcessTasksAsTheyFinish , puis choisissez Définir comme projet de démarrage.

  5. Choisissez la clé F5 pour exécuter le projet.

    Choisissez les touches Ctrl+F5 pour exécuter le projet sans le déboguer.

  6. Exécutez le projet plusieurs fois pour vérifier que les longueurs téléchargées n’apparaissent pas toujours dans le même ordre.

Si vous ne souhaitez pas télécharger le projet, vous pouvez consulter le fichier MainWindow.xaml.vb à la fin de cette rubrique.

Construction de l'exemple

Cet exemple ajoute au code développé dans Cancel Remaining Async Tasks after One Is Complete (Visual Basic) et utilise la même interface utilisateur.

Pour générer l’exemple vous-même, suivez les instructions de la section « Télécharger l’exemple », mais choisissez CancelAfterOneTask comme projet de démarrage. Ajoutez les modifications de cette rubrique à la méthode AccessTheWebAsync de ce projet. Les modifications sont marquées avec des astérisques.

Le projet CancelAfterOneTask inclut déjà une requête qui, lorsqu’elle est exécutée, crée une collection de tâches. Chaque appel à ProcessURLAsync dans le code suivant retourne un Task<TResult>TResult est un entier.

Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
    From url In urlList Select ProcessURLAsync(url, client, ct)  

Dans le fichier MainWindow.xaml.vb du projet, apportez les modifications suivantes à la AccessTheWebAsync méthode.

  • Exécutez la requête en appliquant Enumerable.ToList au lieu de ToArray.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()  
    
  • Ajoutez une boucle while qui effectue les étapes suivantes pour chaque tâche de la collection.

    1. Elle attend un appel à WhenAny pour identifier la première tâche dans la collection afin de terminer son téléchargement.

      Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)  
      
    2. Elle supprime cette tâche de la collection.

      downloadTasks.Remove(finishedTask)  
      
    3. Elle attend finishedTask, qui est retourné par un appel à ProcessURLAsync. La variable finishedTask est une Task<TResult> dans laquelle TReturn est un entier. La tâche est déjà terminée, mais vous l’attendez pour récupérer la longueur du site web téléchargé, comme l’illustre l’exemple suivant.

      Dim length = Await finishedTask  
      resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)  
      

Vous devez exécuter le projet plusieurs fois pour vérifier que les longueurs téléchargées n’apparaissent pas toujours dans le même ordre.

Avertissement

Vous pouvez utiliser WhenAny dans une boucle, comme décrit dans l’exemple, pour résoudre les problèmes impliquant un petit nombre de tâches. Toutefois, d’autres approches sont plus efficaces si vous avez un grand nombre de tâches à traiter. Pour plus d’informations et d’exemples, consultez Traitement des tâches à mesure qu’elles se terminent.

Exemple complet

Le code suivant est le texte complet du fichier MainWindow.xaml.vb pour l’exemple. Les astérisques marquent les éléments qui ont été ajoutés pour cet exemple.

Notez que vous devez ajouter une référence pour System.Net.Http.

Vous pouvez télécharger le projet à partir de l’exemple Async : ajuster votre application.

' Add an Imports directive and a reference for System.Net.Http.  
Imports System.Net.Http  
  
' Add the following Imports directive for System.Threading.  
Imports System.Threading  
  
Class MainWindow  
  
    ' Declare a System.Threading.CancellationTokenSource.  
    Dim cts As CancellationTokenSource  
  
    Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)  
  
        ' Instantiate the CancellationTokenSource.  
        cts = New CancellationTokenSource()  
  
        resultsTextBox.Clear()  
  
        Try  
            Await AccessTheWebAsync(cts.Token)  
            resultsTextBox.Text &= vbCrLf & "Downloads complete."  
  
        Catch ex As OperationCanceledException  
            resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf  
  
        Catch ex As Exception  
            resultsTextBox.Text &= vbCrLf & "Downloads failed." & vbCrLf  
        End Try  
  
        ' Set the CancellationTokenSource to Nothing when the download is complete.  
        cts = Nothing  
    End Sub  
  
    ' You can still include a Cancel button if you want to.  
    Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)  
  
        If cts IsNot Nothing Then  
            cts.Cancel()  
        End If  
    End Sub  
  
    ' Provide a parameter for the CancellationToken.  
    ' Change the return type to Task because the method has no return statement.  
    Async Function AccessTheWebAsync(ct As CancellationToken) As Task  
  
        Dim client As HttpClient = New HttpClient()  
  
        ' Call SetUpURLList to make a list of web addresses.  
        Dim urlList As List(Of String) = SetUpURLList()  
  
        ' ***Create a query that, when executed, returns a collection of tasks.  
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
            From url In urlList Select ProcessURLAsync(url, client, ct)  
  
        ' ***Use ToList to execute the query and start the download tasks.
        Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()  
  
        ' ***Add a loop to process the tasks one at a time until none remain.  
        While downloadTasks.Count > 0  
            ' ***Identify the first task that completes.  
            Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)  
  
            ' ***Remove the selected task from the list so that you don't  
            ' process it more than once.  
            downloadTasks.Remove(finishedTask)  
  
            ' ***Await the first completed task and display the results.  
            Dim length = Await finishedTask  
            resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)  
        End While  
  
    End Function  
  
    ' Bundle the processing steps for a website into one async method.  
    Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)  
  
        ' GetAsync returns a Task(Of HttpResponseMessage).
        Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)  
  
        ' Retrieve the website contents from the HttpResponseMessage.  
        Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()  
  
        Return urlContents.Length  
    End Function  
  
    ' Add a method that creates a list of web addresses.  
    Private Function SetUpURLList() As List(Of String)  
  
        Dim urls = New List(Of String) From  
            {  
                "https://msdn.microsoft.com",  
                "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  
  
End Class  
  
' Sample output:  
  
' Length of the download:  226093  
' Length of the download:  412588  
' Length of the download:  175490  
' Length of the download:  204890  
' Length of the download:  158855  
' Length of the download:  145790  
' Length of the download:  44908  
' Downloads complete.  

Voir aussi