Delen via


Annuleer resterende asynchrone taken nadat één is voltooid (Visual Basic)

Door de Task.WhenAny methode samen met een CancellationTokente gebruiken, kunt u alle resterende taken annuleren wanneer één taak is voltooid. De WhenAny methode gebruikt een argument dat een verzameling taken is. De methode start alle taken en retourneert één taak. De ene taak is voltooid wanneer een taak in de verzameling is voltooid.

Dit voorbeeld laat zien hoe u een annuleringstoken gebruikt in combinatie met WhenAny om de eerste taak uit de verzameling taken te voltooien en de resterende taken te annuleren. Elke taak downloadt de inhoud van een website. In het voorbeeld wordt de lengte weergegeven van de inhoud van de eerste download die moet worden voltooid en worden de andere downloads geannuleerd.

Opmerking

Als u de voorbeelden wilt uitvoeren, moet Visual Studio 2012 of hoger en .NET Framework 4.5 of hoger op uw computer zijn geïnstalleerd.

Het voorbeeld downloaden

U kunt het volledige WPF-project (Windows Presentation Foundation) downloaden uit Async Sample: Uw toepassing verfijnen en vervolgens deze stappen uitvoeren.

  1. Decomprim het bestand dat u hebt gedownload en start Vervolgens Visual Studio.

  2. Kies Bestand, Openen, Project/Oplossing in de menubalk.

  3. In het dialoogvenster Project openen opent u de map met de gedecomprimeerde voorbeeldcode en daarna opent u het oplossingsbestand (.sln) voor AsyncFineTuningVB.

  4. Open in Solution Explorer het snelmenu voor het project CancelAfterOneTask en kies Instellen als Opstartproject.

  5. Kies de F5-sleutel om het project uit te voeren.

    Druk op de toetsen Ctrl+F5 om het project uit te voeren zonder foutopsporing.

  6. Voer het programma meerdere keren uit om te controleren of verschillende downloads eerst zijn voltooid.

Als u het project niet wilt downloaden, kunt u het MainWindow.xaml.vb bestand aan het einde van dit onderwerp bekijken.

Het voorbeeld bouwen

Het voorbeeld in dit onderwerp wordt toegevoegd aan het project dat is ontwikkeld in Een asynchrone taak annuleren of een lijst met taken om een lijst met taken te annuleren. In het voorbeeld wordt dezelfde gebruikersinterface gebruikt, hoewel de knop Annuleren niet expliciet wordt gebruikt.

Als u het voorbeeld zelf wilt bouwen, volgt u stap voor stap de instructies in de sectie 'Het voorbeeld downloaden', maar kiest u CancelAListOfTasks als het opstartproject. Voeg de wijzigingen in dit onderwerp toe aan dat project.

Start in het MainWindow.xaml.vb bestand van het project CancelAListOfTasks de overgang door de verwerkingsstappen voor elke website van de lus AccessTheWebAsync naar de volgende asynchrone methode te verplaatsen.

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

In AccessTheWebAsyncdit voorbeeld wordt een query, de ToArray methode en de WhenAny methode gebruikt om een matrix met taken te maken en te starten. De toepassing van WhenAny op de array retourneert één taak die, wanneer er op gewacht wordt, overeenkomt met de eerste taak die voltooid is in de reeks taken.

Breng de volgende wijzigingen aan in AccessTheWebAsync. Sterretjes markeren de wijzigingen in het codebestand.

  1. Maak commentaar van of verwijder de loop.

  2. Maak een query die, wanneer deze wordt uitgevoerd, een verzameling algemene taken produceert. Elke oproep naar ProcessURLAsync retourneert een Task<TResult> waar TResult een geheel getal is.

    ' ***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. Roep ToArray aan om de query uit te voeren en de taken te starten. De toepassing van de WhenAny methode in de volgende stap zou de query uitvoeren en de taken starten zonder gebruik te maken van ToArray, maar bij andere methoden is dat mogelijk niet het geval. De veiligste procedure is om de uitvoering van de query expliciet af te dwingen.

    ' ***Use ToArray to execute the query and start the download tasks.
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
  4. Roep WhenAny op bij de verzameling taken. WhenAny retourneert een Task(Of Task(Of Integer)) of Task<Task<int>>. Met andere woorden, WhenAny retourneert een taak die resulteert in één Task(Of Integer) of Task<int> wanneer deze wordt aangeroepen. Die ene taak is de eerste taak in de verzameling die moet worden voltooid. De taak die als eerste is voltooid, wordt toegewezen aan finishedTask. Het type van finishedTask is Task<TResult>, waar TResult een geheel getal is, omdat dat het retourtype van ProcessURLAsync is.

    ' ***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. In dit voorbeeld bent u alleen geïnteresseerd in de taak die als eerste is voltooid. CancellationTokenSource.Cancel Gebruik daarom om de resterende taken te annuleren.

    ' ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel()
    
  6. Wacht tot slot totdat finishedTask de lengte van de gedownloade inhoud wordt opgehaald.

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

Voer het programma meerdere keren uit om te controleren of verschillende downloads eerst zijn voltooid.

Volledig voorbeeld

De volgende code is het volledige MainWindow.xaml.vb- of MainWindow.xaml.cs-bestand voor het voorbeeld. Sterretjes markeren de elementen die zijn toegevoegd voor dit voorbeeld.

U moet een verwijzing toevoegen voor System.Net.Http.

U kunt het project downloaden uit Async Sample: Uw toepassing verfijnen.

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

Zie ook