Mehrere Aufgaben starten und nach Abschluss verarbeiten (C# und Visual Basic)

Mit Task.WhenAny verwenden, können Sie mehrere Aufgaben gleichzeitig starten und Verwendung eines nacheinander verarbeiten, während sie anstatt Prozess in der Reihenfolge abgeschlossen werden, in der sie gestartet werden.

Im folgenden Beispiel wird eine Abfrage, eine Auflistung Aufgaben zu erstellen.Jede Aufgabe lädt den Inhalt einer bestimmten Website herunter.In jeder Iteration einer Schleife, gibt ein erwarteter Aufruf WhenAny die Aufgabe in der Auflistung von Aufgaben zurück, die den Download zuerst beendet.Diese Aufgabe aus der Auflistung entfernt wird und verarbeitet.Die Schleifenwiederholungen bis die Auflistung enthält nicht mehr Aufgaben.

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 ProcessTasksAsTheyFinish 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 Projekt aus, mehrmals zu überprüfen, dass die heruntergeladenen Länge nicht immer in der gleichen Reihenfolge angezeigt werden.

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

In diesem Beispiel wird dem Code, der in Verbleibende Aufgaben nach Abschluss einer Aufgabe abbrechen (C# und Visual Basic) entwickelten hinzu und verwendet das gleiche Benutzeroberfläche.

Um das Beispiel zu erstellen, sich schrittweise, folgen Sie den Anweisungen im Abschnitt" Beispiel "Download, aber wählen CancelAfterOneTask als Startprojekt aus.Fügen Sie die Änderungen in diesem Thema auf der AccessTheWebAsync-Methode in diesem Projekt hin hinzu.Die Änderungen werden mit Sternchen gekennzeichnet.

Das CancelAfterOneTask Projekt umfasst bereits eine Abfrage, die, wenn sie ausgeführt wird, eine Auflistung Aufgaben erstellt.Jeder Aufruf von ProcessURLAsync im folgenden Code gibt Task<TResult> zurück, in dem TResult eine ganze Zahl ist.

Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
    From url In urlList Select ProcessURLAsync(url, client, ct)
IEnumerable<Task<int>> downloadTasksQuery =
    from url in urlList select ProcessURL(url, client, ct);

In der MainWindow.xaml.vb- oder "MainWindow.xaml.cs" des Projekts, nehmen Sie die folgenden Änderungen an der AccessTheWebAsync-Methode vor.

  • Führen Sie die Abfrage aus, indem Sie Enumerable.ToList<TSource> anstelle ToArray<TSource> anwenden.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()
    
    List<Task<int>> downloadTasks = downloadTasksQuery.ToList();
    
  • Fügen Sie eine While-Schleife hinzu, die die folgenden Schritte für jede Aufgabe in der Auflistung ausführt.

    1. Erwartet einen Aufruf WhenAny, um die erste Aufgabe in der Auflistung zu identifizieren, den Download abzubrechen.

      Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
      
      Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);
      
    2. Entfernt diese Aufgabe aus der - Auflistung.

      downloadTasks.Remove(firstFinishedTask)
      
      downloadTasks.Remove(firstFinishedTask);
      
    3. Erwartet firstFinishedTask, das durch den Aufruf ProcessURLAsync zurückgegeben wird.Die firstFinishedTask-Variable ist Task<TResult>, in dem TReturn eine ganze Zahl ist.Die Aufgabe ist bereits abgeschlossen, aber Sie erwarten sie, um die Länge der heruntergeladenen Website im folgenden Beispiel gezeigt, abzurufen.

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

Sie sollten das Projekt mehrmals ausführen, um zu überprüfen, ob die heruntergeladenen Länge nicht immer in der gleichen Reihenfolge angezeigt werden.

WarnhinweisVorsicht

Sie können WhenAny in einer Schleife verwenden, wie im Beispiel beschrieben, um Probleme zu lösen, die eine kleine Anzahl Aufgaben einschließen.sind jedoch andere Ansätze effizienter, wenn viele Aufgaben verarbeitet haben.Weitere Informationen und Beispiele finden Sie unter Verarbeiten von Aufgaben, wie sie ausführen.

Vollständiges Beispiel

Der folgende Code ist der vollständige Text der 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 & "Downloads complete."

        Catch ex As OperationCanceledException
            resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf

        Catch ex As Exception
            resultsTextBox.Text &= vbCrLf & "Downloads 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()

        ' ***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 ToList to execute the query and start the download tasks. 
        Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()

        ' ***Add a loop to process the tasks one at a time until none remain.
        While downloadTasks.Count > 0
            ' ***Identify the first task that completes.
            Dim firstFinishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)

            ' ***Remove the selected task from the list so that you don't
            ' process it more than once.
            downloadTasks.Remove(firstFinishedTask)

            ' ***Await the first completed task and display the results.
            Dim length = Await firstFinishedTask
            resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)
        End While

    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 download:  226093
' Length of the download:  412588
' Length of the download:  175490
' Length of the download:  204890
' Length of the download:  158855
' Length of the download:  145790
' Length of the download:  44908
' Downloads 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 ProcessTasksAsTheyFinish
{
    public partial class MainWindow : Window
    {
        // Declare a System.Threading.CancellationTokenSource.
        CancellationTokenSource cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();

            // Instantiate the CancellationTokenSource.
            cts = new CancellationTokenSource();

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

            cts = null;
        }


        private void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
        }


        async Task AccessTheWebAsync(CancellationToken ct)
        {
            HttpClient client = new HttpClient();

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

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

            // ***Use ToList to execute the query and start the tasks. 
            List<Task<int>> downloadTasks = downloadTasksQuery.ToList();

            // ***Add a loop to process the tasks one at a time until none remain.
            while (downloadTasks.Count > 0)
            {
                    // Identify the first task that completes.
                    Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks);

                    // ***Remove the selected task from the list so that you don't
                    // process it more than once.
                    downloadTasks.Remove(firstFinishedTask);

                    // Await the completed task.
                    int length = await firstFinishedTask;
                    resultsTextBox.Text += String.Format("\r\nLength of the download:  {0}", length);
            }
        }


        private List<string> SetUpURLList()
        {
            List<string> urls = new List<string> 
            { 
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/windows/apps/br211380.aspx",
                "https://msdn.microsoft.com/en-us/library/hh290136.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;
        }


        async Task<int> ProcessURL(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;
        }
    }
}

// Sample Output:

// Length of the download:  226093
// Length of the download:  412588
// Length of the download:  175490
// Length of the download:  204890
// Length of the download:  158855
// Length of the download:  145790
// Length of the download:  44908
// Downloads 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