Udostępnij za pośrednictwem


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.

  1. Zdekompresuj pobrany plik, a następnie uruchom program Visual Studio.

  2. Na pasku menu wybierz pozycję Plik, Otwórz, Projekt/Rozwiązanie.

  3. 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.

  4. W Eksplorator rozwiązań otwórz menu skrótów dla projektu CancelAfterOneTask, a następnie wybierz pozycję Ustaw jako projekt startowy.

  5. Wybierz klucz F5, aby uruchomić projekt.

    Wybierz klawisze Ctrl+F5, aby uruchomić projekt bez debugowania.

  6. 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 AccessTheWebAsynctym 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.

  1. Oznacz jako komentarz lub usuń pętlę.

  2. 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)
    
  3. Wywołaj metodę ToArray , aby wykonać zapytanie i uruchomić zadania. Zastosowanie WhenAny metody w następnym kroku spowoduje wykonanie zapytania i uruchomienie zadań bez użycia ToArraymetody , 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()
    
  4. Wywołaj WhenAny kolekcję zadań. WhenAny zwraca wartość lub Task(Of Task(Of Integer))Task<Task<int>>. Oznacza to, że zwraca zadanie, WhenAny które daje w wyniku pojedynczą Task(Of Integer) wartość lub Task<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 elementu finishedTask. Typ finishedTask to Task<TResult> gdzie TResult jest liczbą całkowitą, ponieważ jest to zwracany typ ProcessURLAsync.

    ' ***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)
    
  5. 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()
    
  6. 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.

Zobacz też