Instruções passo a passo: fazer várias solicitações da Web em paralelo e usando Async e Await (C# e Visual Basic)

Em um método assíncrono, as tarefas são iniciadas quando criadas. O operador de Espera (Visual Basic) ou de espera (C#) é aplicado à tarefa no ponto no método onde o processamento não pode continuar até terminar a tarefa. Geralmente, uma tarefa fica aguardando para ser criada, como mostra o exemplo a seguir.

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

No entanto, você pode separar as ações de criar e de aguardar a tarefa se seu programa tiver outro trabalho para realizar que não dependa da conclusão da tarefa.

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

Entre iniciar uma tarefa e esperar por ela, você pode começar outras tarefas. As tarefas adicionais são executadas implicitamente em paralelo, mas nenhum thread adicional é criado.

O programa a seguir inicia três downloads assíncronos da Web e, em seguida, espera-os na ordem em que eles foram chamados. Observe que, quando você executar o programa, as tarefas nem sempre são finalizadas na ordem em que elas são criadas e esperadas. Começam a executar quando são criados, e uma ou mais tarefas podem terminar antes que o método atinja as expressões de espera.

Dica

Para concluir este projeto, você deve ter o Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 for Windows Desktop, Visual Studio Express 2013 para Windows, ou o .NET Framework 4.5 ou 4.5.1 instalado no seu computador.

Para obter um exemplo que inicia várias tarefas ao mesmo tempo, consulte Como estender as instruções passo a passo assíncronas usando Task.WhenAll (C# e Visual Basic).

É possível baixar o código para este exemplo do Exemplos de código do desenvolvedor.

Para configurar o projeto

  • Para configurar um aplicativo de WPF, complete as seguintes etapas. Você pode localizar instruções detalhadas para essas etapas em Instruções passo a passo: acessando a Web e usando Async e Await (C# e Visual Basic).

    • Crie um aplicativo WPF que contém uma caixa de texto e um botão. Nomeie o botão startButton e nomeie a caixa de texto resultsTextBox.

    • Adicione uma referência para System.Net.Http.

    • Em MainWindow.xaml.vb ou em MainWindow.xaml.cs, adicione uma instrução Imports ou uma diretiva using para System.Net.Http.

Para adicionar o código

  1. Na janela de design, MainWindow.xaml, clique duas vezes no botão para criar o manipulador de eventos startButton_Click em MainWindow.xaml.vb ou em MainWindow.xaml.cs. Como alternativa, selecione o botão, selecione o ícone Manipuladores de eventos para elementos selecionados na janela Propriedades, e entre em startButton_Click na caixa de texto Clicar.

  2. Copie o seguinte código e cole-o no corpo de startButton_Click em MainWindow.xaml.vb ou em 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";
    

    O código chama um método assíncrono, CreateMultipleTasksAsync, que conduz o aplicativo.

  3. Adicione os seguintes métodos de suporte ao projeto:

    • ProcessURLAsync usa um método de HttpClient para baixar o conteúdo de um site como uma matriz de bytes. Em seguida, o método de suporte ProcessURLAsync exibe e retorna o tamanho da matriz.

    • DisplayResults exibe o número de bytes na matriz de bytes para cada URL. Esta exibição mostra quando cada tarefa termina de baixar.

    Copie o seguinte métodos e cole-os após o startButton_Click em MainWindow.xaml.vb ou em MainWindow.xaml.cs.

    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. Finalmente, defina o método CreateMultipleTasksAsync, que executa as seguintes etapas.

    • O método declara um objeto de HttpClient, que você precisa para acessar o método GetByteArrayAsync em ProcessURLAsync.

    • O método cria e inicia três tarefas do tipo Task, onde TResult é um número inteiro. Conforme cada tarefa termina, DisplayResults exibe a URL da tarefa e o comprimento dos conteúdo baixados. Como as tarefas estão executando de forma assíncrona, a ordem em que os resultados aparecem pode diferir da ordem em que foram declarados.

    • O método espera a conclusão de cada tarefa. Cada operador Await ou await suspende a execução de CreateMultipleTasksAsync até que a tarefa esperada seja concluída. O operador também recupera o valor de retorno da chamada para ProcessURLAsync de cada tarefa concluída.

    • Quando as tarefas tiverem sido concluídas e os valores inteiros tiverem sido recuperados, o método soma os tamanhos dos sites e exibe o resultado.

    Copie o seguinte método e cole-o em sua solução.

    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. Escolha a tecla F5 para executar o programa e escolha o botão Iniciar.

    Execute o programa várias vezes para verificar se as três tarefas não terminam sempre na mesma ordem e se a ordem em que são concluídas não é necessariamente a ordem em que são criadas e esperadas.

Exemplo

O código a seguir contém o exemplo completo.

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

Consulte também

Tarefas

Instruções passo a passo: acessando a Web e usando Async e Await (C# e Visual Basic)

Como estender as instruções passo a passo assíncronas usando Task.WhenAll (C# e Visual Basic)

Conceitos

Programação assíncrona com Async e Await (C# e Visual Basic)