Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Za pomocą programu Task.WhenAnymożna jednocześnie uruchomić wiele zadań i przetworzyć je jeden po drugim, zamiast przetwarzać je w kolejności, w której są uruchamiane.
W poniższym przykładzie użyto zapytania do utworzenia kolekcji zadań. Każde zadanie pobiera zawartość określonej witryny internetowej. W każdej iteracji pętli while wywołanie WhenAny
, na które czekamy, zwraca zadanie z kolekcji zadań, które jako pierwsze kończy pobieranie. To zadanie jest usuwane z kolekcji i przetwarzane. Pętla powtarza się, dopóki kolekcja nie zawiera więcej zadań.
Uwaga / Notatka
Aby uruchomić przykłady, na komputerze musi być zainstalowany program Visual Studio 2012 lub nowszy oraz program .NET Framework 4.5 lub nowszy.
Pobieranie przykładu
Pełny projekt programu Windows Presentation Foundation (WPF) można pobrać z przykładu Async: Dostosowywanie aplikacji , a następnie wykonaj następujące kroki.
Zdekompresuj pobrany plik, a następnie uruchom program Visual Studio.
Na pasku menu wybierz pozycję Plik, Otwórz, Projekt/Rozwiązanie.
W oknie dialogowym Otwieranie projektu otwórz folder zawierający zdekompresowany przykładowy kod, a następnie otwórz plik rozwiązania (.sln) dla pliku AsyncFineTuningVB.
W Eksploratorze rozwiązań otwórz menu skrótów dla projektu ProcessTasksAsTheyFinish , a następnie wybierz pozycję Ustaw jako projekt startowy.
Wybierz klucz F5, aby uruchomić projekt.
Wybierz Ctrl+F5, aby uruchomić projekt bez debugowania.
Uruchom projekt kilka razy, aby sprawdzić, czy pobrane długości nie zawsze są wyświetlane w tej samej kolejności.
Jeśli nie chcesz pobierać projektu, możesz przejrzeć plik MainWindow.xaml.vb na końcu tego tematu.
Budowanie przykładu
Przykład ten rozszerza kod opracowany w sekcji Anuluj pozostałe zadania asynchroniczne po ukończeniu jednego (Visual Basic) i wykorzystuje ten sam interfejs użytkownika.
Aby utworzyć przykład samodzielnie, krok po kroku, postępuj zgodnie z instrukcjami w sekcji "Pobieranie przykładu", ale wybierz CancelAfterOneTask jako Projekt startowy. Dodaj zmiany z tego tematu do metody AccessTheWebAsync
w tym projekcie. Zmiany są oznaczone gwiazdkami.
Projekt CancelAfterOneTask zawiera już zapytanie, które podczas wykonywania tworzy kolekcję zadań. Każde wywołanie ProcessURLAsync
w poniższym kodzie zwraca Task<TResult>, gdzie TResult
jest liczbą całkowitą.
Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
From url In urlList Select ProcessURLAsync(url, client, ct)
W pliku MainWindow.xaml.vb projektu wprowadź następujące zmiany w metodzie AccessTheWebAsync
.
Wykonaj zapytanie, stosując Enumerable.ToList zamiast ToArray.
Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
Dodaj pętlę czasową, która wykonuje następujące kroki dla każdego zadania w kolekcji.
Oczekuje na wywołanie
WhenAny
, aby zidentyfikować pierwsze zadanie w kolekcji, które jako pierwsze zakończy pobieranie.Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
Usuwa to zadanie z kolekcji.
downloadTasks.Remove(finishedTask)
Awaits
finishedTask
, który jest zwracany przez wywołanie metodyProcessURLAsync
. ZmiennafinishedTask
jest Task<TResult>, gdzieTReturn
jest liczbą całkowitą. Zadanie zostało już ukończone, ale oczekujesz na pobranie długości pobranej witryny internetowej, jak pokazano w poniższym przykładzie.Dim length = Await finishedTask resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website: {0}" & vbCrLf, length)
Należy uruchomić projekt kilka razy, aby sprawdzić, czy pobrane długości nie zawsze są wyświetlane w tej samej kolejności.
Ostrzeżenie
Możesz użyć WhenAny
w pętli, zgodnie z opisem w przykładzie, aby rozwiązać problemy, które obejmują niewielką liczbę zadań. Jednak inne podejścia są bardziej wydajne, jeśli masz dużą liczbę zadań do przetworzenia. Aby uzyskać więcej informacji i przykładów, zobacz Przetwarzanie zadań po ich ukończeniu.
Kompletny przykład
Poniższy kod jest kompletnym tekstem pliku MainWindow.xaml.vb dla przykładu. Gwiazdki oznaczają elementy, które zostały dodane w tym przykładzie.
Zwróć uwagę, że należy dodać odwołanie dla elementu System.Net.Http.
Projekt można pobrać z Asynchroniczny Przykład: Dostrajanie Twojej Aplikacji.
' 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.