Spuštění několika asynchronních úloh a jejich zpracování při jejich dokončení (Visual Basic)
Pomocí nich Task.WhenAnymůžete současně spouštět více úkolů a zpracovávat je po jednom, protože jsou dokončené, a ne je zpracovávat v pořadí, ve kterém jsou spuštěné.
Následující příklad používá dotaz k vytvoření kolekce úloh. Každý úkol stáhne obsah zadaného webu. V každé iteraci smyčky while vrátí očekávané volání WhenAny
úkolu v kolekci úkolů, které dokončí její stahování jako první. Tato úloha se odebere z kolekce a zpracuje se. Smyčka se opakuje, dokud kolekce neobsahuje žádné další úkoly.
Poznámka:
Abyste mohli spustit příklady, musíte mít na počítači nainstalovanou sadu Visual Studio 2012 nebo novější a rozhraní .NET Framework 4.5 nebo novější.
Stažení příkladu
Kompletní projekt Windows Presentation Foundation (WPF) si můžete stáhnout z asynchronní ukázky: Vyladění aplikace a pak postupujte podle těchto kroků.
Dekomprimujte soubor, který jste stáhli, a spusťte Visual Studio.
Na řádku nabídek zvolte Soubor, Otevřít, Projekt nebo Řešení.
V dialogovém okně Otevřít projekt otevřete složku obsahující ukázkový kód, který jste dekomprimovali, a pak otevřete soubor řešení (.sln) pro AsyncFineTuningVB.
V Průzkumník řešení otevřete místní nabídku projektu ProcessTasksAsTheyFinish a pak zvolte Nastavit jako spouštěcí projekt.
Zvolte klávesu F5, aby se projekt spustil.
Pokud chcete projekt spustit bez ladění, zvolte klávesy Ctrl+F5.
Spusťte projekt několikrát, abyste ověřili, že se stažené délky nezobrazují vždy ve stejném pořadí.
Pokud si projekt nechcete stáhnout, můžete si projít MainWindow.xaml.vb soubor na konci tohoto tématu.
Sestavení příkladu
Tento příklad přidá kód vyvinutý ve funkci Zrušit zbývající asynchronní úlohy po dokončení jednoho (Visual Basic) a použije stejné uživatelské rozhraní.
Pokud chcete sestavit příklad sami, postupujte krok za krokem podle pokynů v části "Stažení příkladu", ale jako projekt StartUp zvolte CancelAfterOneTask. Přidejte změny v tomto tématu do AccessTheWebAsync
metody v tomto projektu. Změny jsou označené hvězdičkami.
Projekt CancelAfterOneTask již obsahuje dotaz, který při spuštění vytvoří kolekci úkolů. Každé volání ProcessURLAsync
v následujícím kódu vrátí Task<TResult> celé TResult
číslo.
Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
From url In urlList Select ProcessURLAsync(url, client, ct)
V MainWindow.xaml.vb souboru projektu proveďte následující změny metody AccessTheWebAsync
.
Spusťte dotaz tak, že použijete Enumerable.ToList místo ToArray.
Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
Přidejte smyčku While, která provádí následující kroky pro každou úlohu v kolekci.
Čeká na volání k
WhenAny
identifikaci prvního úkolu v kolekci, aby se dokončilo stahování.Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
Odebere danou úlohu z kolekce.
downloadTasks.Remove(finishedTask)
Awaits
finishedTask
, který je vrácen volánímProcessURLAsync
. ProměnnáfinishedTask
je celé Task<TResult>TReturn
číslo. Úkol je již dokončený, ale očekáváte, že načte délku staženého webu, jak ukazuje následující příklad.Dim length = Await finishedTask resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website: {0}" & vbCrLf, length)
Projekt byste měli spustit několikrát, abyste ověřili, že se stažené délky nezobrazí vždy ve stejném pořadí.
Upozornění
Ve smyčce, jak je popsáno v příkladu, můžete použít WhenAny
k řešení problémů, které zahrnují malý počet úkolů. Pokud ale máte velký počet úkolů ke zpracování, jsou další přístupy efektivnější. Další informace a příklady najdete v tématu Zpracování úloh při jejich dokončení.
Kompletní příklad
Následující kód je úplný text souboru MainWindow.xaml.vb příkladu. Hvězdičky označují prvky přidané v tomto příkladu.
Všimněte si, že je nutné přidat odkaz pro System.Net.Http.
Projekt si můžete stáhnout z asynchronní ukázky: Vyladění aplikace.
' 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.