如何:并行发起多个 Web 请求(C# 和 Visual Basic)

在异步方法,那么,当其创建时,任务启动。等待 (Visual Basic)或 等待 (C#)运算符应用于该点的任务在无法继续处理调用方法,直到任务完成。通常任务等待,在创建了,则,如下例所示。

Dim result = Await someWebAccessMethodAsync(url)
var result = await someWebAccessMethodAsync(url);

但是,您可以从等待任务分离创建任务,如果您的程序具有不依赖于完成完成的其他工作。

' The following line creates and starts the task.
Dim myTask = someWebAccessMethodAsync(url)

' While the task is running, you can do other work that does not depend
' on the results of the task.
' . . . . .

' The application of Await suspends the rest of this method until the task is 
' complete.
Dim result = Await myTask
// The following line creates and starts the task.
var myTask = someWebAccessMethodAsync(url);

// While the task is running, you can do other work that doesn't depend
// on the results of the task.
// . . . . .

// The application of await suspends the rest of this method until the task is complete.
var result = await myTask;

在启动任务和等待它之间,可以开始其他任务。其他任务并行隐式运行的,但是,其他线程不会创建。

下面的过程中启动三个异步web按调用的顺序下载然后等待它们。请注意,那么,当您运行程序,任务不按顺序总是完成其创建并等待。它们开始运行,当其创建时,因此,一个或多个任务可能完成,方法到达等待表达式之前。

有关同时启动多个任务的其他示例,请参见 如何:使用 Task.WhenAll 扩展演练(C# 和 Visual Basic)

若要完成此项,您必须在计算机上安装 Visual Studio 2012 才能。有关更多信息,请参见 Microsoft 网站

可以下载此示例的中的代码。开发人员代码示例

设置项目

  • 若要设置WPF应用程序,请完成以下步骤。可以找到这些步骤的详细说明。演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)

    • 创建包含文本框和一个按钮上的WPF应用程序。将按钮 startButton,并将文本框 resultsTextBox。

    • 添加 System.Net.Http的引用。

    • 在MainWindow.xaml.vb或MainWindow.xaml.cs中,添加一个 Imports 语句或 using 指令 System.Net.Http的。

添加代码

  1. 在"设计"窗口,MainWindow.xaml,在MainWindow.xaml.vb或MainWindow.xaml.cs双击按钮以创建 startButton_Click 事件处理程序。或者,选择按钮,选择。属性 窗口的 *** 所选元素的事件处理程序 *** 图标,然后输入 startButton_Click 在 *** 单击 *** 文本框。

  2. 复制下面的代码,并将其粘贴到 startButton_Click 主体在MainWindow.xaml.vb或MainWindow.xaml.cs的。

    resultsTextBox.Clear()
    Await CreateMultipleTasksAsync()
    resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    
    resultsTextBox.Clear();
    await CreateMultipleTasksAsync();
    resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
    

    代码调用异步方法,CreateMultipleTasksAsync,驱动应用程序。

  3. 添加以下方法支持到该项目中:

    • ProcessURLAsync 使用一个 HttpClient 方法下载网站内容作为字节数组。支持方法,ProcessURLAsync 然后显示并返回数组的长度。

    • DisplayResults 显示中的字节数字节数组的每个URL的。此显示每个任务完成下载。

    复制以下方法,并在MainWindow.xaml.vb或MainWindow.xaml.cs的 startButton_Click 事件处理程序后处理将它们粘贴。

    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
    
    async Task<int> ProcessURLAsync(string url, HttpClient client)
    {
        var byteArray = await client.GetByteArrayAsync(url);
        DisplayResults(url, byteArray);
        return byteArray.Length;
    }
    
    
    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);
    }
    
  4. 最后,定义方法 CreateMultipleTasksAsync,执行下列步骤。

    • 方法声明 HttpClient 对象,需要在 ProcessURLAsync的访问方法 GetByteArrayAsync

    • 方法创建并启动类型 Task<TResult>三个任务,TResult 是整数。在每个任务完成,DisplayResults 显示下载内容的任务的URL和长度。由于任务以异步方式运行,结果出现的顺序可能与声明它们的顺序不同。

    • 方法等待每项任务的完成。每 Await 或 await 运算符挂起 CreateMultipleTasksAsync 的执行,直到等待任务完成。运算符从调用来检索返回值到每个已完成的任务的 ProcessURLAsync。

    • 当任务完成后,并整数值检索出,该方法总网站的长度并显示结果。

    复制以下方法,并将其粘贴到您的解决方案。

    Private Async Function CreateMultipleTasksAsync() 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}
    
        ' Create and start the tasks. As each task finishes, DisplayResults 
        ' displays its length.
        Dim download1 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com", client)
        Dim download2 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client)
        Dim download3 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client)
    
        ' Await each task.
        Dim length1 As Integer = Await download1
        Dim length2 As Integer = Await download2
        Dim length3 As Integer = Await download3
    
        Dim total As Integer = length1 + length2 + length3
    
        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function
    
    private async Task CreateMultipleTasksAsync()
    {
        // Declare an HttpClient object, and increase the buffer size. The
        // default buffer size is 65,536.
        HttpClient client =
            new HttpClient() { MaxResponseContentBufferSize = 1000000 };
    
        // Create and start the tasks. As each task finishes, DisplayResults 
        // displays its length.
        Task<int> download1 = 
            ProcessURLAsync("https://msdn.microsoft.com", client);
        Task<int> download2 = 
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client);
        Task<int> download3 = 
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client);
    
        // Await each task.
        int length1 = await download1;
        int length2 = await download2;
        int length3 = await download3;
    
        int total = length1 + length2 + length3;
    
        // Display the total count for the downloaded websites.
        resultsTextBox.Text +=
            string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);
    }
    
  5. 选择F5键运行程序,然后选择 *** 启动 *** 按钮。

    运行程序多次验证三个任务不以相同顺序总是完成,并且它们完成的顺序不一定是其创建并等待的顺序。

示例

下面的代码包括完整的示例。

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


Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click
        resultsTextBox.Clear()
        Await CreateMultipleTasksAsync()
        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    End Sub


    Private Async Function CreateMultipleTasksAsync() 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}

        ' Create and start the tasks. As each task finishes, DisplayResults 
        ' displays its length.
        Dim download1 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com", client)
        Dim download2 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client)
        Dim download3 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client)

        ' Await each task.
        Dim length1 As Integer = Await download1
        Dim length2 As Integer = Await download2
        Dim length3 As Integer = Await download3

        Dim total As Integer = length1 + length2 + length3

        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    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
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 the following using directive, and add a reference for System.Net.Http.
using System.Net.Http;


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

        private async void startButton_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Clear();
            await CreateMultipleTasksAsync();
            resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
        }


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

            // Create and start the tasks. As each task finishes, DisplayResults 
            // displays its length.
            Task<int> download1 = 
                ProcessURLAsync("https://msdn.microsoft.com", client);
            Task<int> download2 = 
                ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client);
            Task<int> download3 = 
                ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client);

            // Await each task.
            int length1 = await download1;
            int length2 = await download2;
            int length3 = await download3;

            int total = length1 + length2 + length3;

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


        async Task<int> ProcessURLAsync(string url, HttpClient client)
        {
            var byteArray = await client.GetByteArrayAsync(url);
            DisplayResults(url, byteArray);
            return byteArray.Length;
        }


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

请参见

任务

演练:使用 Async 和 Await 访问 Web(C# 和 Visual Basic)

如何:使用 Task.WhenAll 扩展演练(C# 和 Visual Basic)

概念

使用 Async 和 Await 的异步编程(C# 和 Visual Basic)