Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Używając metody Task.WhenAny razem z elementem CancellationToken, można anulować wszystkie pozostałe zadania, gdy jedno z zadań zostanie ukończone. Metoda WhenAny przyjmuje argument, który jest kolekcją zadań. Metoda uruchamia wszystkie zadania i zwraca jedno zadanie. Pojedyncze zadanie jest ukończone po zakończeniu dowolnego zadania w kolekcji.
W tym przykładzie pokazano, jak używać tokenu anulowania w połączeniu z WhenAny, aby zatrzymać pierwsze ukończone zadanie z kolekcji zadań i anulować pozostałe zadania. Każde zadanie pobiera zawartość witryny internetowej. W przykładzie wyświetlana jest długość zawartości pierwszego zakończonego pobierania oraz następuje anulowanie pozostałych pobrań.
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 CancelAfterOneTask , a następnie wybierz pozycję Ustaw jako projekt startowy.
Wybierz klucz F5, aby uruchomić projekt.
Wybierz Ctrl+F5, aby uruchomić projekt bez debugowania.
Uruchom program kilka razy, aby sprawdzić, czy różne pobrania zakończą się najpierw.
Jeśli nie chcesz pobierać projektu, możesz przejrzeć plik MainWindow.xaml.vb na końcu tego tematu.
Budowanie przykładu
Przykład w tym temacie jest dodany do projektu opracowanego w temacie Anulowanie zadania asynchronicznego lub listy zadań w celu anulowania listy zadań. W przykładzie użyto tego samego interfejsu użytkownika, chociaż przycisk Anuluj nie jest używany jawnie.
Aby utworzyć przykład samodzielnie, postępuj zgodnie z instrukcjami w sekcji "Pobieranie przykładu", ale wybierz pozycję CancelAListOfTasks jako projekt startowy. Dodaj zmiany w tym temacie do tego projektu.
W pliku MainWindow.xaml.vb projektu CancelAListOfTasks rozpocznij przekonwertowanie, przenosząc kroki przetwarzania dla każdej witryny internetowej z pętli w AccessTheWebAsync do następującej metody asynchronicznej.
' ***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
W AccessTheWebAsync tym przykładzie użyto zapytania, metody ToArray oraz metody WhenAny do utworzenia i uruchomienia tablicy działań. Aplikacja WhenAny do tablicy zwraca pojedyncze zadanie, które, gdy będzie oczekiwane, oceni się jako pierwsze zadanie osiągające ukończenie w tablicy zadań.
Wprowadź następujące zmiany w pliku AccessTheWebAsync. Gwiazdki oznaczają zmiany w pliku kodu.
Zakomentować lub usunąć pętlę.
Utwórz zapytanie, które po wykonaniu powoduje utworzenie kolekcji zadań ogólnych. Każde wywołanie
ProcessURLAsynczwraca Task<TResult>, gdzieTResultjest liczbą całkowitą.' ***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)Wywołaj metodę
ToArray, aby wykonać zapytanie i uruchomić zadania. Zastosowanie metodyWhenAnyw następnym kroku spowoduje wykonanie zapytania i uruchomienie zadań bez użyciaToArray, ale inne metody mogą tego nie zrobić. Najbezpieczniejszą praktyką jest wymusić jawne wykonanie zapytania.' ***Use ToArray to execute the query and start the download tasks. Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()Wywołaj
WhenAnykolekcję zadań.WhenAnyzwraca wartość,Task(Of Task(Of Integer))lubTask<Task<int>>. Oznacza to, żeWhenAnyzwraca zadanie, które po oczekiwaniu rozstrzyga się do pojedynczej wartościTask(Of Integer)lubTask<int>. To jedno zadanie jest pierwszym zadaniem w kolekcji, które należy zakończyć. Zadanie, które zakończyło się najpierw, jest przypisane do elementufinishedTask. TypfinishedTaskto Task<TResult> gdzieTResultjest liczbą całkowitą, ponieważ jest to zwracany typProcessURLAsync.' ***Call WhenAny and then await the result. The task that finishes ' first is assigned to finishedTask. Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)W tym przykładzie interesuje Cię tylko zadanie, które zostanie ukończone jako pierwsze. W związku z tym użyj polecenia CancellationTokenSource.Cancel , aby anulować pozostałe zadania.
' ***Cancel the rest of the downloads. You just want the first one. cts.Cancel()Na koniec poczekaj
finishedTaskna pobranie długości pobranej zawartości.Dim length = Await finishedTask resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website: {length}" & vbCrLf
Uruchom program kilka razy, aby sprawdzić, czy różne pobrania zakończą się najpierw.
Kompletny przykład
Poniższy kod to kompletny plik MainWindow.xaml.vb lub MainWindow.xaml.cs 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 & "Download complete."
Catch ex As OperationCanceledException
resultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf
Catch ex As Exception
resultsTextBox.Text &= vbCrLf & "Download 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()
'' Comment out or delete the loop.
''For Each url In urlList
'' ' GetAsync returns a Task(Of HttpResponseMessage).
'' ' Argument ct carries the message if the Cancel button is chosen.
'' ' Note that the Cancel button can cancel all remaining downloads.
'' Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
'' ' Retrieve the website contents from the HttpResponseMessage.
'' Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
'' resultsTextBox.Text &=
'' vbCrLf & $"Length of the downloaded string: {urlContents.Length}." & vbCrLf
''Next
' ***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 ToArray to execute the query and start the download tasks.
Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
' ***Call WhenAny and then await the result. The task that finishes
' first is assigned to finishedTask.
Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
' ***Cancel the rest of the downloads. You just want the first one.
cts.Cancel()
' ***Await the first completed task and display the results
' Run the program several times to demonstrate that different
' websites can finish first.
Dim length = Await finishedTask
resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website: {length}" & vbCrLf
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 downloaded website: 158856
' Download complete.