Gewusst wie: Erweitern der asynchronen exemplarischen Vorgehensweise mit Task.WhenAll (C# und Visual Basic)

Sie können die Leistung der asynchronen Projektmappe in Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await (C# und Visual Basic) verbessern, indem Sie die Task.WhenAll-Methode verwenden. Diese Methode wartet auf mehrere asynchrone Vorgänge, die als Auflistung von Aufgaben dargestellt werden.

Sie haben möglicherweise in der exemplarischen Vorgehensweise bemerkt, dass die Websites Downloads in verschiedenen Geschwindigkeiten anbieten. Manchmal ist eine Website sehr langsam und verzögert alle verbleibenden Downloads. Wenn Sie die asynchronen Projektmappen ausführen, die Sie in der exemplarischen Vorgehensweise erstellt haben, können Sie das Programm einfach beenden, wenn Sie nicht warten möchten. Eine bessere Option wäre jedoch, alle Downloads gleichzeitig zu starten und schnellere Downloads einfach fortfahren, ohne auf langsamere zu warten.

Sie wenden die Task.WhenAll-Methode auf eine Aufgabenauflistung an. Die Anwendung von WhenAll gibt eine einzelne Aufgabe zurück, die nicht abgeschlossen ist, bevor jede Aufgabe in der Auflistung abgeschlossen ist. Die Aufgaben scheinen parallel ausgeführt zu werden, es werden jedoch keine weiteren Threads erstellt. Die Aufgaben können in jeder Reihenfolge abschließen.

Wichtig

Die folgenden Prozeduren beschreiben Erweiterungen zu asynchronen Anwendungen, die in Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await (C# und Visual Basic) entwickelt werden.Sie können die Anwendungen entwickeln, indem Sie entweder die exemplarische Vorgehensweise durcharbeiten oder den Code von Codebeispiele für Entwickler herunterladen.

Zum Ausführen des Beispiels muss Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 für Windows Desktop Visual Studio Express 2013 für Windows oder .NET Framework 4.5 bzw. 4.5.1 auf dem Computer installiert sein.

So fügen Sie der GetURLContentsAsync-Lösung Task.WhenAll hinzu

  1. Fügen Sie die ProcessURLAsync-Methode der ersten Anwendung hinzu, die in Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await (C# und Visual Basic) entwickelt wird.

    • Wenn Sie die Codebeispiele für Entwickler heruntergeladen haben, öffnen Sie das "AsyncWalkthrough"-Projekt und fügen Sie dann ProcessURLAsync entweder der "MainWindow.xaml.vb"- oder "MainWindow.xaml.cs"-Datei hinzu.

    • Wenn Sie den Code innerhalb der exemplarische Vorgehensweise entwickelt haben, fügen Sie ProcessURLAsync der Anwendung hinzu, die die GetURLContentsAsync-Methode enthält. Die "MainWindow.xaml.vb"- oder "MainWindow.xaml.cs"-Datei für diese Anwendung ist das erste Beispiel im Abschnitt "Vollständige Codebeispiele der exemplarischen Vorgehensweise".

    Die ProcessURLAsync-Methode konsolidiert die Aktionen im Text der For Each- oder foreach-Schleife in SumPageSizesAsync in der ersten exemplarischen Vorgehensweise. Die Methode lädt asynchron den angegebenen Inhalt einer Website als Bytearray und gibt dann die Länge des Bytearrays zurück.

    Private Async Function ProcessURLAsync(url As String) As Task(Of Integer)
    
        Dim byteArray = Await GetURLContentsAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function
    
    private async Task<int> ProcessURLAsync(string url)
    {
        var byteArray = await GetURLContentsAsync(url);
        DisplayResults(url, byteArray);
        return byteArray.Length;
    }
    
  2. Kommentieren Sie die Schleife For Each oder foreach in SumPageSizesAsync aus oder löschen Sie sie, wie der folgenden Code zeigt.

    'Dim total = 0 
    'For Each url In urlList 
    
    '    Dim urlContents As Byte() = Await GetURLContentsAsync(url) 
    
    '    ' The previous line abbreviates the following two assignment statements. 
    
    '    ' GetURLContentsAsync returns a task. At completion, the task 
    '    ' produces a byte array. 
    '    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url) 
    '    'Dim urlContents As Byte() = Await getContentsTask 
    
    '    DisplayResults(url, urlContents) 
    
    '    ' Update the total. 
    '    total += urlContents.Length 
    'Next
    
    //var total = 0; 
    //foreach (var url in urlList) 
    //{ 
    //    byte[] urlContents = await GetURLContentsAsync(url); 
    
    //    // The previous line abbreviates the following two assignment statements. 
    //    // GetURLContentsAsync returns a Task<T>. At completion, the task 
    //    // produces a byte array. 
    //    //Task<byte[]> getContentsTask = GetURLContentsAsync(url); 
    //    //byte[] urlContents = await getContentsTask; 
    
    //    DisplayResults(url, urlContents); 
    
    //    // Update the total.           
    //    total += urlContents.Length; 
    //}
    
  3. Erstellen Sie eine Auflistung von Aufgaben. Der folgende Code definiert eine Abfrage, die beim Ausführen durch die ToArray``1-Methode eine Aufgabenauflistung erstellt, die die Inhalte jeder Website herunterladen. Die Aufgaben werden beim Auswerten der Abfrage gestartet.

    Fügen Sie nach der Deklaration von urlList den folgenden Code der SumPageSizesAsync-Methode hinzu:

    ' Create a query.  
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
        From url In urlList Select ProcessURLAsync(url)
    
    ' Use ToArray to execute the query and start the download tasks. 
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
    // Create a query. 
    IEnumerable<Task<int>> downloadTasksQuery = 
        from url in urlList select ProcessURLAsync(url);
    
    // Use ToArray to execute the query and start the download tasks.
    Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
    
  4. Wenden Sie Task.WhenAll auf die Auflistung von Aufgaben downloadTasks an. Task.WhenAll gibt eine einzelne abgeschlossene Aufgabe zurück, wenn alle Aufgaben in der Auflistung abgeschlossen wurden.

    Im folgenden Beispiel erwartet der Await- oder await-Ausdruck den Abschluss der einzelnen Aufgabe, die WhenAll zurückgibt. Der Ausdruck wird gegen ein Array mit ganzen Zahlen ausgewertet, wobei jede ganze Zahl die Länge einer heruntergeladenen Website ist. Fügen Sie SumPageSizesAsync den folgenden Code hinzu, direkt nach dem im vorherigen Schritt hinzugefügten Code.

    ' Await the completion of all the running tasks. 
    Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)
    
    '' The previous line is equivalent to the following two statements. 
    'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks) 
    'Dim lengths As Integer() = Await whenAllTask
    
    // Await the completion of all the running tasks. 
    int[] lengths = await Task.WhenAll(downloadTasks);
    
    //// The previous line is equivalent to the following two statements. 
    //Task<int[]> whenAllTask = Task.WhenAll(downloadTasks); 
    //int[] lengths = await whenAllTask;
    
  5. Abschließend verwenden Sie die Sum-Methode, um die Summe der Größen aller Websites zu berechnen. Fügen Sie SumPageSizesAsync die folgende Zeile hinzu.

    Dim total = lengths.Sum()
    
    int total = lengths.Sum();
    

So fügen Sie der HttpClient.GetByteArrayAsync-Lösung Task.WhenAll hinzu

  1. Fügen Sie die folgende Version von ProcessURLAsync der zweiten Anwendung hinzu, die in Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await (C# und Visual Basic) entwickelt wird.

    • Wenn Sie den Code von Codebeispiele für Entwickler heruntergeladen haben, öffnen Sie das "AsyncWalkthrough_HttpClient"-Projekt und fügen dann ProcessURLAsync entweder der "MainWindow.xaml.vb"- oder "MainWindow.xaml.cs"-Datei hinzu.

    • Wenn Sie den Code innerhalb der exemplarische Vorgehensweise entwickelt haben, fügen Sie ProcessURLAsync der Anwendung hinzu, die die HttpClient.GetByteArrayAsync-Methode verwendet. Die "MainWindow.xaml.vb"- oder "MainWindow.xaml.cs"-Datei für diese Anwendung ist das zweite Beispiel im Abschnitt "Vollständige Codebeispiele der exemplarischen Vorgehensweise".

    Die ProcessURLAsync-Methode konsolidiert die Aktionen im Text der For Each- oder foreach-Schleife in SumPageSizesAsync in der ersten exemplarischen Vorgehensweise. Die Methode lädt asynchron den angegebenen Inhalt einer Website als Bytearray und gibt dann die Länge des Bytearrays zurück.

    Der einzige Unterschied der ProcessURLAsync-Methode in der vorherigen Prozedur ist die Verwendung der HttpClient-Instanz, client.

    Private Async Function ProcessURLAsync(url As String, client As HttpClient) As Task(Of Integer)
    
        Dim byteArray = Await client.GetByteArrayAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function
    
    async Task<int> ProcessURL(string url, HttpClient client)
    {
        byte[] byteArray = await client.GetByteArrayAsync(url);
        DisplayResults(url, byteArray);
        return byteArray.Length;
    }
    
  2. Kommentieren Sie die Schleife For Each oder foreach in SumPageSizesAsync aus oder löschen Sie sie, wie der folgenden Code zeigt.

    'Dim total = 0 
    'For Each url In urlList 
    '    ' GetByteArrayAsync returns a task. At completion, the task 
    '    ' produces a byte array. 
    '    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url) 
    
    '    ' The following two lines can replace the previous assignment statement. 
    '    'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url) 
    '    'Dim urlContents As Byte() = Await getContentsTask 
    
    '    DisplayResults(url, urlContents) 
    
    '    ' Update the total. 
    '    total += urlContents.Length 
    'Next
    
    //var total = 0; 
    //foreach (var url in urlList) 
    //{ 
    //    // GetByteArrayAsync returns a Task<T>. At completion, the task 
    //    // produces a byte array. 
    //    byte[] urlContent = await client.GetByteArrayAsync(url); 
    
    //    // The previous line abbreviates the following two assignment 
    //    // statements. 
    //    Task<byte[]> getContentTask = client.GetByteArrayAsync(url); 
    //    byte[] urlContent = await getContentTask; 
    
    //    DisplayResults(url, urlContent); 
    
    //    // Update the total. 
    //    total += urlContent.Length; 
    //}
    
  3. Definieren Sie eine Abfrage, die beim Ausführen durch die ToArray``1-Methode eine Aufgabenauflistung erstellt, die die Inhalte jeder Website herunterladen. Die Aufgaben werden beim Auswerten der Abfrage gestartet.

    Fügen Sie nach der Deklaration von client und urlList den folgenden Code der SumPageSizesAsync-Methode hinzu:

    ' Create a query. 
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
        From url In urlList Select ProcessURLAsync(url, client)
    
    ' Use ToArray to execute the query and start the download tasks. 
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
    // Create a query.
    IEnumerable<Task<int>> downloadTasksQuery = 
        from url in urlList select ProcessURL(url, client);
    
    // Use ToArray to execute the query and start the download tasks.
    Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
    
  4. Wenden Sie Task.WhenAll auf die Auflistung von Aufgaben an, downloadTasks. Task.WhenAll gibt eine einzelne abgeschlossene Aufgabe zurück, wenn alle Aufgaben in der Auflistung abgeschlossen wurden.

    Im folgenden Beispiel erwartet der Await- oder await-Ausdruck den Abschluss der einzelnen Aufgabe, die WhenAll zurückgibt. Wenn vollständig, wertet der Await- oder der await-Ausdruck als Ergebnis ein Array von ganzen Zahlen aus, wobei jede ganze Zahl die Länge einer heruntergeladenen Website ist. Fügen Sie SumPageSizesAsync den folgenden Code hinzu, direkt nach dem im vorherigen Schritt hinzugefügten Code.

    ' Await the completion of all the running tasks. 
    Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)
    
    '' The previous line is equivalent to the following two statements. 
    'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks) 
    'Dim lengths As Integer() = Await whenAllTask
    
    // Await the completion of all the running tasks. 
    int[] lengths = await Task.WhenAll(downloadTasks);
    
    //// The previous line is equivalent to the following two statements. 
    //Task<int[]> whenAllTask = Task.WhenAll(downloadTasks); 
    //int[] lengths = await whenAllTask;
    
  5. Abschließend verwenden Sie die Sum-Methode, um die Summe der Größen aller Websites zu berechnen. Fügen Sie SumPageSizesAsync die folgende Zeile hinzu.

    Dim total = lengths.Sum()
    
    int total = lengths.Sum();
    

So testen Sie die Task.WhenAll-Lösungen

Beispiel

Der folgende Code zeigt die Erweiterungen des Projekts, das die GetURLContentsAsync-Methode verwendet, um Inhalt aus dem Web herunterladen.

' Add the following Imports statements, and add a reference for System.Net.Http. 
Imports System.Net.Http
Imports System.Net
Imports System.IO


Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        resultsTextBox.Clear()

        ' One-step async call.
        Await SumPageSizesAsync()

        '' Two-step async call. 
        'Dim sumTask As Task = SumPageSizesAsync() 
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click." 
    End Sub 


    Private Async Function SumPageSizesAsync() As Task

        ' Make a list of web addresses. 
        Dim urlList As List(Of String) = SetUpURLList()

        ' Create a query.  
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
            From url In urlList Select ProcessURLAsync(url)

        ' Use ToArray to execute the query and start the download tasks. 
        Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()

        ' You can do other work here before awaiting. 

        ' Await the completion of all the running tasks. 
        Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)

        '' The previous line is equivalent to the following two statements. 
        'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks) 
        'Dim lengths As Integer() = Await whenAllTask 

        Dim total = lengths.Sum()

        'Dim total = 0 
        'For Each url In urlList 

        '    Dim urlContents As Byte() = Await GetURLContentsAsync(url) 

        '    ' The previous line abbreviates the following two assignment statements. 

        '    ' GetURLContentsAsync returns a task. At completion, the task 
        '    ' produces a byte array. 
        '    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url) 
        '    'Dim urlContents As Byte() = Await getContentsTask 

        '    DisplayResults(url, urlContents) 

        '    ' Update the total. 
        '    total += urlContents.Length 
        'Next 

        ' Display the total count for all of the web addresses.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function 


    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/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "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 


    ' The actions from the foreach loop are moved to this async method. 
    Private Async Function ProcessURLAsync(url As String) As Task(Of Integer)

        Dim byteArray = Await GetURLContentsAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function 


    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())

        ' The downloaded resource ends up in the variable named content. 
        Dim content = New MemoryStream()

        ' Initialize an HttpWebRequest for the current URL. 
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)

        ' Send the request to the Internet resource and wait for 
        ' the response. 
        Using response As WebResponse = Await webReq.GetResponseAsync()
            ' Get the data stream that is associated with the specified URL. 
            Using responseStream As Stream = response.GetResponseStream()
                ' Read the bytes in responseStream and copy them to content.   
                ' CopyToAsync returns a Task, not a Task<T>.
                Await responseStream.CopyToAsync(content)
            End Using 
        End Using 

        ' Return the result as a byte array. 
        Return content.ToArray()
    End Function 



    Private Sub DisplayResults(url As String, content As Byte())

        ' Display the length of each website. The string format  
        ' is designed to be used with a monospaced font, such as 
        ' Lucida Console or Global Monospace. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub 

End Class
// Add the following using directives, and add a reference for System.Net.Http. 
using System.Net.Http;
using System.IO;
using System.Net;

namespace AsyncExampleWPF_WhenAll
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }


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

            // Two-step async call.
            Task sumTask = SumPageSizesAsync();
            await sumTask;

            // One-step async call. 
            //await SumPageSizesAsync();

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";
        }


        private async Task SumPageSizesAsync()
        {
            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();

            // Create a query. 
            IEnumerable<Task<int>> downloadTasksQuery = 
                from url in urlList select ProcessURLAsync(url);

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

            // You can do other work here before awaiting. 

            // Await the completion of all the running tasks. 
            int[] lengths = await Task.WhenAll(downloadTasks);

            //// The previous line is equivalent to the following two statements. 
            //Task<int[]> whenAllTask = Task.WhenAll(downloadTasks); 
            //int[] lengths = await whenAllTask; 

            int total = lengths.Sum();

            //var total = 0; 
            //foreach (var url in urlList) 
            //{ 
            //    byte[] urlContents = await GetURLContentsAsync(url); 

            //    // The previous line abbreviates the following two assignment statements. 
            //    // GetURLContentsAsync returns a Task<T>. At completion, the task 
            //    // produces a byte array. 
            //    //Task<byte[]> getContentsTask = GetURLContentsAsync(url); 
            //    //byte[] urlContents = await getContentsTask; 

            //    DisplayResults(url, urlContents); 

            //    // Update the total.           
            //    total += urlContents.Length; 
            //} 

            // Display the total count for all of the websites.
            resultsTextBox.Text +=
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
        }


        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/ee256749.aspx",
                "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;
        }



        // The actions from the foreach loop are moved to this async method. 
        private async Task<int> ProcessURLAsync(string url)
        {
            var byteArray = await GetURLContentsAsync(url);
            DisplayResults(url, byteArray);
            return byteArray.Length;
        }


        private async Task<byte[]> GetURLContentsAsync(string url)
        {
            // The downloaded resource ends up in the variable named content. 
            var content = new MemoryStream();

            // Initialize an HttpWebRequest for the current URL. 
            var webReq = (HttpWebRequest)WebRequest.Create(url);

            // Send the request to the Internet resource and wait for 
            // the response. 
            using (WebResponse response = await webReq.GetResponseAsync())
            {
                // Get the data stream that is associated with the specified url. 
                using (Stream responseStream = response.GetResponseStream())
                {
                    await responseStream.CopyToAsync(content);
                }
            }

            // Return the result as a byte array. 
            return content.ToArray();

        }


        private void DisplayResults(string url, byte[] content)
        {
            // Display the length of each website. The string format  
            // is designed to be used with a monospaced font, such as 
            // Lucida Console or Global Monospace. 
            var bytes = content.Length;
            // Strip off the "http://".
            var displayURL = url.Replace("http://", "");
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);

        }
    }
}

Der folgende Code zeigt die Erweiterungen des Projekts, das die HttpClient.GetByteArrayAsync-Methode verwendet, um Inhalt aus dem Web herunterladen.

' Add the following Imports statements, and add a reference for System.Net.Http. 
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        resultsTextBox.Clear()

        '' One-step async call.
        Await SumPageSizesAsync()

        '' Two-step async call. 
        'Dim sumTask As Task = SumPageSizesAsync() 
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click." 
    End Sub 


    Private Async Function SumPageSizesAsync() As Task

        ' Declare an HttpClient object and increase the buffer size. The 
        ' default buffer size is 65,536. 
        Dim client As HttpClient =
            New HttpClient() With {.MaxResponseContentBufferSize = 1000000}

        ' Make a list of web addresses. 
        Dim urlList As List(Of String) = SetUpURLList()

        ' Create a query. 
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
            From url In urlList Select ProcessURLAsync(url, client)

        ' Use ToArray to execute the query and start the download tasks. 
        Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()

        ' You can do other work here before awaiting. 

        ' Await the completion of all the running tasks. 
        Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)

        '' The previous line is equivalent to the following two statements. 
        'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks) 
        'Dim lengths As Integer() = Await whenAllTask 

        Dim total = lengths.Sum()

        'Dim total = 0 
        'For Each url In urlList 
        '    ' GetByteArrayAsync returns a task. At completion, the task 
        '    ' produces a byte array. 
        '    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url) 

        '    ' The following two lines can replace the previous assignment statement. 
        '    'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url) 
        '    'Dim urlContents As Byte() = Await getContentsTask 

        '    DisplayResults(url, urlContents) 

        '    ' Update the total. 
        '    total += urlContents.Length 
        'Next 

        ' Display the total count for all of the web addresses.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function 


    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "http://www.msdn.com",
                "https://msdn.microsoft.com/en-us/library/hh290136.aspx",
                "https://msdn.microsoft.com/en-us/library/ee256749.aspx",
                "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 

    Private Async Function ProcessURLAsync(url As String, client As HttpClient) As Task(Of Integer)

        Dim byteArray = Await client.GetByteArrayAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function 


    Private Sub DisplayResults(url As String, content As Byte())

        ' Display the length of each website. The string format  
        ' is designed to be used with a monospaced font, such as 
        ' Lucida Console or Global Monospace. 
        Dim bytes = content.Length
        ' Strip off the "http://". 
        Dim displayURL = url.Replace("http://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub 

End Class
// Add the following using directives, and add a reference for System.Net.Http. 
using System.Net.Http;
using System.IO;
using System.Net;

namespace AsyncExampleWPF_HttpClient_WhenAll
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

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

            // One-step async call.
            await SumPageSizesAsync();

            // Two-step async call. 
            //Task sumTask = SumPageSizesAsync(); 
            //await sumTask;

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";
        }


        private async Task SumPageSizesAsync()
        {
            // Make a list of web addresses.
            List<string> urlList = SetUpURLList();


            // Declare an HttpClient object and increase the buffer size. The 
            // default buffer size is 65,536.
            HttpClient client = new HttpClient() { MaxResponseContentBufferSize = 1000000 };

            // Create a query.
            IEnumerable<Task<int>> downloadTasksQuery = 
                from url in urlList select ProcessURL(url, client);

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

            // You can do other work here before awaiting. 

            // Await the completion of all the running tasks. 
            int[] lengths = await Task.WhenAll(downloadTasks);

            //// The previous line is equivalent to the following two statements. 
            //Task<int[]> whenAllTask = Task.WhenAll(downloadTasks); 
            //int[] lengths = await whenAllTask; 

            int total = lengths.Sum();

            //var total = 0; 
            //foreach (var url in urlList) 
            //{ 
            //    // GetByteArrayAsync returns a Task<T>. At completion, the task 
            //    // produces a byte array. 
            //    byte[] urlContent = await client.GetByteArrayAsync(url); 

            //    // The previous line abbreviates the following two assignment 
            //    // statements. 
            //    Task<byte[]> getContentTask = client.GetByteArrayAsync(url); 
            //    byte[] urlContent = await getContentTask; 

            //    DisplayResults(url, urlContent); 

            //    // Update the total. 
            //    total += urlContent.Length; 
            //} 

            // Display the total count for all of the web addresses.
            resultsTextBox.Text +=
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
        }


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


        // The actions from the foreach loop are moved to this async method.
        async Task<int> ProcessURL(string url, HttpClient client)
        {
            byte[] byteArray = await client.GetByteArrayAsync(url);
            DisplayResults(url, byteArray);
            return byteArray.Length;
        }


        private void DisplayResults(string url, byte[] content)
        {
            // Display the length of each web site. The string format  
            // is designed to be used with a monospaced font, such as 
            // Lucida Console or Global Monospace. 
            var bytes = content.Length;
            // Strip off the "http://".
            var displayURL = url.Replace("http://", "");
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
        }
    }
}

Siehe auch

Aufgaben

Exemplarische Vorgehensweise: Zugreifen auf das Web mit Async und Await (C# und Visual Basic)

Referenz

Task.WhenAll