Dela via


Avbryt återstående asynkrona uppgifter när en är klar (Visual Basic)

Genom att Task.WhenAny använda metoden tillsammans med en CancellationTokenkan du avbryta alla återstående aktiviteter när en uppgift är klar. Metoden WhenAny tar ett argument som är en samling uppgifter. Metoden startar alla aktiviteter och returnerar en enda uppgift. Den enda uppgiften är klar när en uppgift i samlingen är klar.

Det här exemplet visar hur du använder en annulleringstoken tillsammans med WhenAny för att hålla fast vid den första uppgiften för att slutföra från samlingen med aktiviteter och avbryta de återstående aktiviteterna. Varje uppgift laddar ned innehållet på en webbplats. I exemplet visas längden på innehållet i den första nedladdningen som ska slutföras och de andra nedladdningarna avbryts.

Kommentar

Om du vill köra exemplen måste du ha Visual Studio 2012 eller senare och .NET Framework 4.5 eller senare installerat på datorn.

Ladda ned exemplet

Du kan ladda ned hela WPF-projektet (Windows Presentation Foundation) från Async Sample: Fine Tuning Your Application och sedan följa dessa steg.

  1. Expandera filen som du laddade ned och starta sedan Visual Studio.

  2. På menyraden väljer du Arkiv, Öppna, Projekt/Lösning.

  3. I dialogrutan Öppna projekt öppnar du mappen som innehåller exempelkoden som du dekomprimerade och öppnar sedan lösningsfilen (.sln) för AsyncFineTuningVB.

  4. I Solution Explorer öppnar du snabbmenyn för projektet CancelAfterOneTask och väljer sedan Ange som startprojekt.

  5. Välj F5-nyckeln för att köra projektet.

    Välj Ctrl+F5-tangenterna för att köra projektet utan att felsöka det.

  6. Kör programmet flera gånger för att kontrollera att olika nedladdningar slutförs först.

Om du inte vill ladda ned projektet kan du granska filen MainWindow.xaml.vb i slutet av det här avsnittet.

Skapa exemplet

Exemplet i det här avsnittet lägger till i projektet som har utvecklats i Avbryt en Async-uppgift eller en lista över aktiviteter för att avbryta en lista över aktiviteter. I exemplet används samma användargränssnitt, även om knappen Avbryt inte används explicit.

Om du vill skapa exemplet själv följer du anvisningarna i avsnittet "Ladda ned exemplet" steg för steg, men väljer AvbrytAListOfTasks som StartUp-projekt. Lägg till ändringarna i det här avsnittet i projektet.

I den MainWindow.xaml.vb filen i projektet CancelAListOfTasks startar du övergången genom att flytta bearbetningsstegen för varje webbplats från loopen till AccessTheWebAsync följande asynkron metod.

' ***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

I AccessTheWebAsyncanvänder det här exemplet en fråga, ToArray metoden och WhenAny metoden för att skapa och starta en matris med uppgifter. Programmet WhenAny för till matrisen returnerar en enda uppgift som, när den väntar, utvärderas till den första uppgiften för att slutföras i matrisen med aktiviteter.

Gör följande ändringar i AccessTheWebAsync. Asterisker markerar ändringarna i kodfilen.

  1. Kommentera ut eller ta bort loopen.

  2. Skapa en fråga som när den körs skapar en samling allmänna uppgifter. Varje anrop till ProcessURLAsync returnerar ett Task<TResult> var TResult är ett heltal.

    ' ***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. Anropa ToArray för att köra frågan och starta aktiviteterna. Tillämpningen av WhenAny metoden i nästa steg skulle köra frågan och starta aktiviteterna utan att använda ToArray, men andra metoder kanske inte gör det. Den säkraste metoden är att tvinga fram körning av frågan explicit.

    ' ***Use ToArray to execute the query and start the download tasks.
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
  4. Anropa WhenAny samlingen med uppgifter. WhenAny returnerar en Task(Of Task(Of Integer)) eller Task<Task<int>>. Returnerar alltså WhenAny en uppgift som utvärderas till en enskild Task(Of Integer) uppgift eller Task<int> när den väntar. Den enda uppgiften är den första uppgiften i samlingen som ska slutföras. Uppgiften som slutfördes först tilldelas till finishedTask. Typen av finishedTask är Task<TResult> där TResult är ett heltal eftersom det är returtypen ProcessURLAsyncför .

    ' ***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. I det här exemplet är du bara intresserad av den uppgift som slutförs först. Använd CancellationTokenSource.Cancel därför för att avbryta de återstående aktiviteterna.

    ' ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel()
    
  6. Slutligen väntar du på finishedTask att hämta längden på det nedladdade innehållet.

    Dim length = Await finishedTask
    resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website:  {length}" & vbCrLf
    

Kör programmet flera gånger för att kontrollera att olika nedladdningar slutförs först.

Fullständigt exempel

Följande kod är den fullständiga MainWindow.xaml.vb- eller MainWindow.xaml.cs-filen för exemplet. Asterisker markerar de element som lades till i det här exemplet.

Observera att du måste lägga till en referens för System.Net.Http.

Du kan ladda ned projektet från Async Sample: Finjustering av ditt program.

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

Se även