Meerdere asynchrone taken starten en deze verwerken wanneer ze zijn voltooid (Visual Basic)
Met behulp van Task.WhenAnykunt u meerdere taken tegelijk starten en ze één voor één verwerken terwijl ze zijn voltooid in plaats van ze te verwerken in de volgorde waarin ze worden gestart.
In het volgende voorbeeld wordt een query gebruikt om een verzameling taken te maken. Elke taak downloadt de inhoud van een opgegeven website. In elke iteratie van een tijdjelus retourneert een wachtende aanroep om de taak te WhenAny
retourneren in de verzameling taken die het downloaden van de taak als eerste hebben voltooid. Deze taak wordt verwijderd uit de verzameling en verwerkt. De lus wordt herhaald totdat de verzameling geen taken meer bevat.
Notitie
Als u de voorbeelden wilt uitvoeren, moet Visual Studio 2012 of hoger en .NET Framework 4.5 of hoger op uw computer zijn geïnstalleerd.
Het voorbeeld downloaden
U kunt het volledige WPF-project (Windows Presentation Foundation) downloaden uit Async Sample: Uw toepassing verfijnen en vervolgens deze stappen uitvoeren.
Decomprim het bestand dat u hebt gedownload en start Vervolgens Visual Studio.
Kies Bestand, Openen, Project/Oplossing in de menubalk.
Open in het dialoogvenster Project openen de map met de voorbeeldcode die u hebt gedecomprimeerd en open het oplossingsbestand (.sln) voor AsyncFineTuningVB.
Open in Solution Explorer het snelmenu voor het project ProcessTasksAsTheyFinish en kies Instellen als Opstartproject.
Kies de F5-sleutel om het project uit te voeren.
Kies de Ctrl+F5-toetsen om het project uit te voeren zonder fouten op te sporen.
Voer het project meerdere keren uit om te controleren of de gedownloade lengten niet altijd in dezelfde volgorde worden weergegeven.
Als u het project niet wilt downloaden, kunt u het MainWindow.xaml.vb bestand aan het einde van dit onderwerp bekijken.
Het voorbeeld bouwen
In dit voorbeeld wordt de code toegevoegd die is ontwikkeld in Resterende asynchrone taken annuleren nadat one is voltooid (Visual Basic) en dezelfde gebruikersinterface gebruikt.
Als u het voorbeeld zelf wilt maken, volgt u stap voor stap de instructies in de sectie 'Het voorbeeld downloaden', maar kiest u CancelAfterOneTask als het opstartproject. Voeg de wijzigingen in dit onderwerp toe aan de AccessTheWebAsync
methode in dat project. De wijzigingen worden gemarkeerd met sterretjes.
Het project CancelAfterOneTask bevat al een query die, wanneer deze wordt uitgevoerd, een verzameling taken maakt. Elke aanroep naar ProcessURLAsync
in de volgende code retourneert een Task<TResult> where TResult
is een geheel getal.
Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
From url In urlList Select ProcessURLAsync(url, client, ct)
Breng in het MainWindow.xaml.vb bestand van het project de volgende wijzigingen aan in de AccessTheWebAsync
methode.
Voer de query uit door deze toe te passen Enumerable.ToList in plaats van ToArray.
Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
Voeg een tijdjelus toe die de volgende stappen uitvoert voor elke taak in de verzameling.
Wacht op een aanroep om de eerste taak in de verzameling te
WhenAny
identificeren om het downloaden te voltooien.Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
Hiermee verwijdert u die taak uit de verzameling.
downloadTasks.Remove(finishedTask)
Wacht op
finishedTask
, die wordt geretourneerd door een oproep naarProcessURLAsync
. DefinishedTask
variabele is een Task<TResult> geheelTReturn
getal. De taak is al voltooid, maar u wacht erop om de lengte van de gedownloade website op te halen, zoals in het volgende voorbeeld wordt weergegeven.Dim length = Await finishedTask resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website: {0}" & vbCrLf, length)
U moet het project meerdere keren uitvoeren om te controleren of de gedownloade lengten niet altijd in dezelfde volgorde worden weergegeven.
Let op
U kunt in een lus, zoals beschreven in het voorbeeld, gebruiken WhenAny
om problemen op te lossen die betrekking hebben op een klein aantal taken. Andere benaderingen zijn echter efficiënter als u een groot aantal taken moet verwerken. Zie Verwerkingstaken wanneer ze zijn voltooid voor meer informatie en voorbeelden.
Volledig voorbeeld
De volgende code is de volledige tekst van het MainWindow.xaml.vb-bestand voor het voorbeeld. Sterretjes markeren de elementen die zijn toegevoegd voor dit voorbeeld.
U moet een verwijzing toevoegen voor System.Net.Http.
U kunt het project downloaden uit Async Sample: Uw toepassing verfijnen.
' 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.