Freigeben über


Verbleibende Aufgaben nach Abschluss einer Aufgabe abbrechen (C# und Visual Basic)

Mithilfe der Task.WhenAny-Methode zusammen mit CancellationToken auswählen, können Sie alle übrigen Aufgaben abbrechen, wenn eine Aufgabe abgeschlossen ist.Die WhenAny-Methode übernimmt ein Argument, das eine Auflistung Aufgaben ist.Die - Methode startet alle Aufgaben und gibt eine einzelne Aufgabe zurück.Die einzelne Aufgabe ist abgeschlossen, wenn jede Aufgabe in der Auflistung abgeschlossen ist.

Dieses Beispiel zeigt, wie Sie ein Abbruchtoken in Verbindung mit WhenAny verwendet, um auf die erste Aufgabe enthält, aus der Auflistung von Aufgaben beenden und die übrigen Aufgaben abzubrechen.Jede Aufgabe lädt den Inhalt einer Website herunter.Im Beispiel wird die Länge des Inhalts des ersten Downloads an, und bricht die anderen Downloads ab.

HinweisHinweis

Um die Beispiele auszuführen, müssen Sie Visual Studio 2012, Visual Studio Express 2012 für Windows Desktop oder .NET Framework 4.5 enthalten, das auf dem Computer installiert ist.

Herunterladen des Beispiels

Sie können das gesamte Projekt (Windows Presentation Foundation) von Asynchrones Beispiel: Abstimmen der Anwendung herunterladen und dann diesen Schritten folgen.

  1. Dekomprimieren Sie die Datei, die Sie heruntergeladen haben, und starten Sie dann Visual Studio 2012.

  2. Klicken Sie in der Menüleiste auf Datei, dann auf Öffnen und Projekt/Projektmappe.

  3. Im Dialogfeld Projekt öffnen öffnen Sie den Ordner, der den Beispielcode enthält, den Sie dekomprimierten und dann die Projektmappendatei (.sln) für AsyncFineTuningCS oder AsyncFineTuningVB öffnet.

  4. In Projektmappen-Explorer öffnen Sie das Kontextmenü für das CancelAfterOneTask Projekt, und wählen Sie dann Als Startprojekt festlegen aus.

  5. Wählen Sie die F5-TASTE, um das Projekt auszuführen.

    Wählen Sie die STRG+F5-Tasten, um das Projekt auszuführen, ohne es zu debuggen.

  6. Führen Sie das Programm mehrmals ausgeführt werden, zu überprüfen, dass verschiedene Downloads zuvor beenden.

Wenn Sie nicht das Projekt herunterladen möchten, können Sie die MainWindow.xaml.vb- und MainWindow.xaml.cs-Dateien am Ende dieses Themas überprüfen.

Erstellen des Beispiels

Das Beispiel in diesem Thema fügt dem Projekt hinzu, das in Eine Aufgabe oder Aufgabenliste abbrechen (C# und Visual Basic) entwickelt wurde, um eine Liste von Aufgaben abzubrechen.Im Beispiel wird das gleiche Benutzeroberfläche, obwohl die Schaltfläche Abbrechen nicht explizit verwendet wird.

Um das Beispiel zu erstellen, sich schrittweise, folgen Sie den Anweisungen im Abschnitt" Beispiel "Download, aber wählen CancelAListOfTasks als Startprojekt aus.Fügen Sie die Änderungen in diesem Thema zu diesem Projekt hin hinzu.

In der MainWindow.xaml.vb- oder CancelAListOfTasks "MainWindow.xaml.cs" des Projekts, starten Sie den Übergang, indem Sie die Verarbeitung Schritte für jede Website von der Schleife in AccessTheWebAsync zur späteren asynchronen Methode verschieben.

' ***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
// ***Bundle the processing steps for a website into one async method.
async Task<int> ProcessURLAsync(string url, HttpClient client, CancellationToken ct)
{
    // GetAsync returns a Task<HttpResponseMessage>. 
    HttpResponseMessage response = await client.GetAsync(url, ct);

    // Retrieve the website contents from the HttpResponseMessage.
    byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

    return urlContents.Length;
}

In AccessTheWebAsync wird in diesem Beispiel eine Abfrage, die ToArray<TSource>WhenAny-Methode und die - Methode, um ein Array Aufgaben zu erstellen und zu starten.Die Verwendung von WhenAny in das Array wird eine einzelne Aufgabe zurück, die, wenn sie erwartet wird, in der ersten Aufgabe, Vervollständigung im Array von Aufgaben zu erreichen ergibt.

Nehmen Sie die folgenden Änderungen in AccessTheWebAsync vor.Sternchen kennzeichnen die Änderungen in der Codedatei.

  1. Kommentieren Sie out oder löschen Sie die Schleife.

  2. Erstellen Sie eine Abfrage, die, wenn sie ausgeführt wird, eine generische Auflistung Aufgaben erzeugt.Jeder Aufruf von gibt ProcessURLAsyncTask<TResult> zurück, in dem TResult eine ganze Zahl ist.

    ' ***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)
    
    // ***Create a query that, when executed, returns a collection of tasks.
    IEnumerable<Task<int>> downloadTasksQuery =
        from url in urlList select ProcessURLAsync(url, client, ct);
    
  3. Rufen Sie ToArray auf, um die Abfrage auszuführen und die Aufgaben zu starten.Die Anwendung der WhenAny-Methode wird im nächsten Schritt würde die Abfrage ausführen und die Aufgaben beginnen, ohne ToArray zu verwenden, andere Methoden können nicht.Die sicherste Praxis ist, die Ausführung der Abfrage explizit zu erzwingen.

    ' ***Use ToArray to execute the query and start the download tasks. 
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
    // ***Use ToArray to execute the query and start the download tasks. 
    Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
    
  4. Aufruf WhenAny in der Auflistung von Aufgaben.WhenAny gibt Task(Of Task(Of Integer)) oder Task<Task<int>> zurück.Das bedeutet, dass WhenAny eine Aufgabe zurück, die zu einzelnen Task(Of Integer) oder zu Task<int> ergibt, wenn es erwartet wurde.Diese einzelne Aufgabe ist die erste Aufgabe in der Auflistung zu beenden.firstFinishedTask die Aufgabe, die beendet wurde, wird zuerst zugewiesen.Der Typ von firstFinishedTask ist Task<TResult>, in dem TResult eine ganze Zahl ist, da der Rückgabetyp von ProcessURLAsync ist.

    ' ***Call WhenAny and then await the result. The task that finishes 
    ' first is assigned to firstFinishedTask.
    Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
    
    // ***Call WhenAny and then await the result. The task that finishes 
    // first is assigned to firstFinishedTask.
    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
    
  5. In diesem Beispiel sind Sie nur für die Aufgabe interessiert, die zuerst beendet.Daher verwendet CancellationTokenSource.Cancel, die übrigen Aufgaben abzubrechen.

    ' ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel()
    
    // ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel();
    
  6. Schließlich erwarten Sie firstFinishedTask, um die Länge des Inhalts heruntergeladenen abzurufen.

    Dim length = Await firstFinishedTask
    resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
    
    var length = await firstFinishedTask;
    resultsTextBox.Text += String.Format("\r\nLength of the downloaded website:  {0}\r\n", length);
    

Führen Sie das Programm mehrmals ausgeführt werden, zu überprüfen, dass verschiedene Downloads zuvor beenden.

Vollständiges Beispiel

Der folgende Code ist die vollständige MainWindow.xaml.vb- oder "MainWindow.xaml.cs" für das Beispiel.Sternchen kennzeichnen die Elemente, die für dieses Beispiel hinzugefügt wurden.

Beachten Sie, dass Sie einen Verweis für System.Net.Http hinzufügen müssen.

Sie können das Projekt von Asynchrones Beispiel: Abstimmen der Anwendung herunterladen.

' 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 &=
        ''        String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, urlContents.Length)
        ''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 firstFinishedTask.
        Dim firstFinishedTask 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 firstFinishedTask
        resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
    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/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            }
        Return urls
    End Function

End Class


' Sample output:

' Length of the downloaded website:  158856

' Download complete.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add a using directive and a reference for System.Net.Http.
using System.Net.Http;

// Add the following using directive.
using System.Threading;

namespace CancelAfterOneTask
{
    public partial class MainWindow : Window
    {
        // Declare a System.Threading.CancellationTokenSource.
        CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }


        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the CancellationTokenSource.
            cts = new CancellationTokenSource();

            resultsTextBox.Clear();

            try
            {
                await AccessTheWebAsync(cts.Token);
                resultsTextBox.Text += "\r\nDownload complete.";
            }
            catch (OperationCanceledException)
            {
                resultsTextBox.Text += "\r\nDownload canceled.";
            }
            catch (Exception)
            {
                resultsTextBox.Text += "\r\nDownload failed.";
            }

            // Set the CancellationTokenSource to null when the download is complete.
            cts = null;
        }


        // You can still include a Cancel button if you want to.
        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
        }


        // Provide a parameter for the CancellationToken.
        async Task AccessTheWebAsync(CancellationToken ct)
        {
            HttpClient client = new HttpClient();

            // Call SetUpURLList to make a list of web addresses.
            List<string> urlList = SetUpURLList();

            // ***Comment out or delete the loop.
            //foreach (var url in urlList)
            //{
            //    // GetAsync returns a Task<HttpResponseMessage>. 
            //    // Argument ct carries the message if the Cancel button is chosen. 
            //    // ***Note that the Cancel button can cancel all remaining downloads.
            //    HttpResponseMessage response = await client.GetAsync(url, ct);

            //    // Retrieve the website contents from the HttpResponseMessage.
            //    byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

            //    resultsTextBox.Text +=
            //        String.Format("\r\nLength of the downloaded string: {0}.\r\n", urlContents.Length);
            //}

            // ***Create a query that, when executed, returns a collection of tasks.
            IEnumerable<Task<int>> downloadTasksQuery =
                from url in urlList select ProcessURLAsync(url, client, ct);

            // ***Use ToArray to execute the query and start the download tasks. 
            Task<int>[] downloadTasks = downloadTasksQuery.ToArray();

            // ***Call WhenAny and then await the result. The task that finishes 
            // first is assigned to firstFinishedTask.
            Task<int> firstFinishedTask = 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.
            var length = await firstFinishedTask;
            resultsTextBox.Text += String.Format("\r\nLength of the downloaded website:  {0}\r\n", length);
        }


        // ***Bundle the processing steps for a website into one async method.
        async Task<int> ProcessURLAsync(string url, HttpClient client, CancellationToken ct)
        {
            // GetAsync returns a Task<HttpResponseMessage>. 
            HttpResponseMessage response = await client.GetAsync(url, ct);

            // Retrieve the website contents from the HttpResponseMessage.
            byte[] urlContents = await response.Content.ReadAsByteArrayAsync();

            return urlContents.Length;
        }


        // Add a method that creates a list of web addresses.
        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/en-us/library/hh290138.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290140.aspx",
                "https://msdn.microsoft.com/en-us/library/dd470362.aspx",
                "https://msdn.microsoft.com/en-us/library/aa578028.aspx",
                "https://msdn.microsoft.com/en-us/library/ms404677.aspx",
                "https://msdn.microsoft.com/en-us/library/ff730837.aspx"
            };
            return urls;
        }
    }
    // Sample output:

    // Length of the downloaded website:  158856

    // Download complete.
}

Siehe auch

Referenz

WhenAny

Konzepte

Feinabstimmung der Async-Anwendung (C# und Visual Basic)

Asynchrone Programmierung mit Async und Await (C# und Visual Basic)

Weitere Ressourcen

Asynchrones Beispiel: Abstimmen der Anwendung