Anulowanie pozostałych zadań asynchronicznych po zakończeniu jednego (Visual Basic)
Używając metody razem z elementem CancellationToken, można anulować wszystkie pozostałe zadania po zakończeniu Task.WhenAny jednego zadania. 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
w celu przechowywania pierwszego zadania w celu zakończenia od kolekcji zadań i anulowania pozostałych zadań. Każde zadanie pobiera zawartość witryny internetowej. W przykładzie wyświetlana jest długość zawartości pierwszego pobierania do ukończenia i anulowanie innych pobrań.
Uwaga
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 Eksplorator 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 klawisze 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.
Kompilowanie 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 przejście, przenosząc kroki przetwarzania dla każdej witryny internetowej z pętli do AccessTheWebAsync
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, ToArray metody i WhenAny
metody do utworzenia i uruchomienia tablicy zadań. Aplikacja WhenAny
do tablicy zwraca pojedyncze zadanie, które w oczekiwanym czasie daje w wyniku pierwsze zadanie, aby osiągnąć ukończenie w tablicy zadań.
Wprowadź następujące zmiany w pliku AccessTheWebAsync
. Gwiazdki oznaczają zmiany w pliku kodu.
Oznacz jako komentarz lub usuń pętlę.
Utwórz zapytanie, które po wykonaniu powoduje utworzenie kolekcji zadań ogólnych. Każde wywołanie funkcji zwraca
ProcessURLAsync
liczbę całkowitą, gdzie Task<TResult>TResult
.' ***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. ZastosowanieWhenAny
metody w następnym kroku spowoduje wykonanie zapytania i uruchomienie zadań bez użyciaToArray
metody , ale inne metody mogą nie. 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
WhenAny
kolekcję zadań.WhenAny
zwraca wartość lubTask(Of Task(Of Integer))
Task<Task<int>>
. Oznacza to, że zwraca zadanie,WhenAny
które daje w wyniku pojedyncząTask(Of Integer)
wartość lubTask<int>
gdy jest oczekiwana. To jedno zadanie to pierwsze zadanie w kolekcji do zakończenia. Zadanie, które zakończyło się najpierw, jest przypisane do elementufinishedTask
. TypfinishedTask
to Task<TResult> gdzieTResult
jest 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
finishedTask
na pobranie 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 przykładu asynchronicznego: dostrajanie 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.