共用方式為


如何:使用 Task.WhenAll 擴充非同步逐步解說的內容 (C# 和 Visual Basic)

您可以使用 Task.WhenAll 方法,改善 逐步解說:使用 Async 和 Await 存取 Web (C# 和 Visual Basic) 中非同步方案的效能。 這個方法會以非同步方式等候多個非同步作業 (代表工作集合)。

您在本逐步解說中可能已經注意到網站下載具有不同的速率。 有時其中一個網站的速度很慢,而拖慢了所有其餘下載。 當您執行您在本逐步解說中建立的非同步方案時,您可以輕易地結束程式 (如果您不要等候),不過較好的選擇是同時啟動任何下載並讓較快的下載繼續執行,而不等待延遲的下載。

您將 Task.WhenAll 方法套用至工作集合。 應用 WhenAll 會傳回未完成的單一工作,直到集合中的每一個工作完成。 工作似乎平行地執行,但是不會建立其他執行緒。 工作可以以任何順序完成。

重要

下列程序描述在逐步解說:使用 Async 和 Await 存取 Web (C# 和 Visual Basic) 中開發的非同步應用程式的擴充。您可以完成這個逐步解說或從開發人員程式碼範例下載程式碼,以開發應用程式。

若要執行範例,您必須將 Visual Studio 2012、Visual Studio 2013、Visual Studio Express 2012 for Windows Desktop、Visual Studio Express 2013 for Windows 或 .NET Framework 4.5 或 4.5.1 安裝在您的電腦上。

將 Task.WhenAll 加入至您的 GetURLContentsAsync 方案

  1. 將 ProcessURLAsync 方法加入至逐步解說:使用 Async 和 Await 存取 Web (C# 和 Visual Basic) 所開發的第一個應用程式。

    • 如果已從開發人員程式碼範例 (英文) 下載程式碼,開啟 AsyncWalkthrough 專案,然後將 ProcessURLAsync 加入至 MainWindow.xaml.vb 或 MainWindow.xaml.cs 檔案。

    • 如果您藉由完成這個逐步解說開發了程式碼,請將 ProcessURLAsync 加入至包含 GetURLContentsAsync 方法的應用程式。 這個應用程式的 MainWindow.xaml.vb 或 MainWindow.xaml.cs 檔案是<逐步解說中完整的程式碼範例>一節中的第一個範例。

    ProcessURLAsync 方法會合併原始解說中 SumPageSizesAsync 的 For Each 主體或 foreach 迴圈主體的動作。 方法會以非同步方式將指定網站的內容下載為位元組陣列,然後顯示並傳回位元組陣列的長度。

    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. 將 SumPageSizesAsync 中的 For Each 或 foreach 迴圈標記為註解或刪除,如下列程式碼所示。

    '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. 建立工作的集合。 下列程式碼會定義查詢,當 ToArray``1 方法執行時,該查詢會建立工作集合來下載每個網站的內容。 工作會在評估查詢時開始。

    將下列程式碼加入至 SumPageSizesAsync 類別,放在 urlList 宣告之後。

    ' 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. 將 Task.WhenAll 套用至工作集合 downloadTasks。 Task.WhenAll 傳回當工作集合中所有工作完成後才會完成的單一工作。

    在下列範例中,Await 或 await 運算式會等候 WhenAll 傳回的單一工作完成。 運算式計算結果為整數的陣列,每個整數都是可下載網站的長度。 將下列程式碼加入至 SumPageSizesAsync,就放在上一個步驟中加入的程式碼之後。

    ' 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. 最後,使用 Sum 方法來計算所有網站的長度總和。 將下列程式碼行加入至 SumPageSizesAsync。

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

加入 Task.WhenAll HttpClient.GetByteArrayAsync 方案

  1. 將下列版本的 ProcessURLAsync 加入至逐步解說:使用 Async 和 Await 存取 Web (C# 和 Visual Basic) 所開發的第二個應用程式。

    • 如果已從開發人員程式碼範例 (英文) 下載程式碼,開啟 AsyncWalkthrough_HttpClient 專案,然後將 ProcessURLAsync 加入至 MainWindow.xaml.vb 或 MainWindow.xaml.cs 檔案。

    • 如果您藉由完成這個逐步解說開發了程式碼,請將 ProcessURLAsync 加入至使用 HttpClient.GetByteArrayAsync 方法的應用程式。 這個應用程式的 MainWindow.xaml.vb 或 MainWindow.xaml.cs 檔案是<逐步解說中完整的程式碼範例>一節中的第二個範例。

    ProcessURLAsync 方法會合併原始解說中 SumPageSizesAsync 的 For Each 主體或 foreach 迴圈主體的動作。 方法會以非同步方式將指定網站的內容下載為位元組陣列,然後顯示並傳回位元組陣列的長度。

    與 ProcessURLAsync 方法的唯一差異是在上一個程序是使用 HttpClient 執行個體: 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. 將 SumPageSizesAsync 中的 For Each 或 foreach 迴圈標記為註解或刪除,如下列程式碼所示。

    '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. 定義查詢,這個查詢由 ToArray``1 方法執行時,會建立下載每個網站內容的工作集合。 工作會在評估查詢時開始。

    將下列程式碼加入至方法 SumPageSizesAsync,放在 client 和 urlList 宣告之後:

    ' 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. 接著將 Task.WhenAll 套用至工作集合 downloadTasks。 Task.WhenAll 傳回當工作集合中所有工作完成後才會完成的單一工作。

    在下列範例中,Await 或 await 運算式會等候 WhenAll 傳回的單一工作完成。 當完成時,Await 或 await 運算式會評估整數陣列,其中每個整數都是已下載網站的長度。 將下列程式碼加入至 SumPageSizesAsync,就放在上一個步驟中加入的程式碼之後。

    ' 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. 最後,使用 Sum 方法來取得所有網站的長度總和。 將下列程式碼行加入至 SumPageSizesAsync。

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

測試 Task.WhenAll 方案

範例

下列程式碼顯示專案擴充,其使用 GetURLContentsAsync 方法從 Web 下載內容。

' 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);

        }
    }
}

下列程式碼顯示專案擴充,其使用方法 HttpClient.GetByteArrayAsync 從 Web 下載內容。

' 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);
        }
    }
}

請參閱

工作

逐步解說:使用 Async 和 Await 存取 Web (C# 和 Visual Basic)

參考

Task.WhenAll