Condividi tramite


Procedura: effettuare più richieste Web in parallelo tramite Async e Await (C# e Visual Basic)

In un metodo asincrono, le attività si avviano quando vengono create. L'operatore Attendere (Visual Basic) o attendere (C#) viene applicato all'attività nel punto del metodo in cui l'elaborazione non può continuare finché l'attività non viene completata. Spesso un'attività rimane in attesa non appena viene creata, come illustrato di seguito.

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

Tuttavia, è possibile separare la creazione dell'attività dall'attesa di un'altra attività se il vostro programma ha altri processi da svolgere che non dipendono dal completamento dell'attività.

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

Tra l'avvio di un'attività e la sua messa in attesa, è possibile avviare altre attività. Le attività aggiuntive vengono eseguite in parallelo, ma in modo implicito: non viene creato nessun thread aggiuntivo.

Il seguente programma inizia con tre download asincroni dal Web e li mette in attesa a seconda dell'ordine in cui sono chiamati. Avviso: quando si esegue il programma, le attività non vengono sempre terminate nell'ordine in cui vengono create e messe in attesa. Verranno eseguiti quando verranno creati, e uno o più attività potrebbero essere completate prima che il metodo raggiunga le espressioni di attesa.

Nota

Per completare questo progetto, è necessario che Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 per Windows Desktop,Visual Studio Express 2013 per Windows o .NET Framework 4.5 o 4.5.1 siano installati sul computer.

Per un altro esempio che avvii più operazioni contemporaneamente, vedere Procedura: estendere la procedura dettagliata asincrona tramite Task.WhenAll (C# e Visual Basic).

È possibile scaricare il codice per questo esempio dalla pagina degli esempi di codice per gli sviluppatori.

Per impostare il progetto

  • Per impostare un'applicazione WPF, completare i seguenti passaggi. E' possibile trovare istruzioni dettagliate per questa procedura in Procedura dettagliata: accesso al Web tramite Async e Await (C# e Visual Basic).

    • Creare un'applicazione WPF che contenga una casella di testo e un pulsante. Denominare il pulsante con il nome startButtone la casella di testo con resultsTextBox.

    • Aggiungere un riferimento per System.Net.Http.

    • Nel file MainWindow.xaml.vb o MainWindow.xaml.cs, aggiungere un'istruzione Imports o una direttiva using per System.Net.Http.

Per aggiungere il codice

  1. Nella finestra di progettazione, fare doppio clic sul pulsante per creare il gestore di eventi startButton_Click nel file MainWindow.Xaml.vb o MainWindow.xaml.cs. In alternativa, selezionare il pulsante, selezionare l'icona Gestore eventi per gli elementi selezionati nella finestra Proprietà quindi immettere startButton_Clic nella casella di testo Clic.

  2. Copiare il seguente codice e incollarlo nel corpo di startButton_Click nel file MainWindow.xaml.vb o 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";
    

    Il codice chiama un metodo asincrono, CreateMultipleTasksAsync, che pilota l'applicazione.

  3. Aggiungere il seguente metodo di supporto al progetto:

    • ProcessURLAsync utilizza un metodo HttpClient per scaricare il contenuto di un sito Web come array di byte. Il metodo di supporto ProcessURLAsync ,quindi, Visualizza e restituisce la lunghezza dell'array.

    • DisplayResults visualizza il numero di byte nell'array di byte per ogni URL. Questa visualizzazione mostra quando ogni attività termina il download.

    Copiare i seguenti metodi e incollarli dopo il gestore eventi startButton_Click nel file MainWindow.xaml.vb o 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. Infine, definire il metodo CreateMultipleTasksAsync, che esegue i seguenti passi.

    • Il metodo dichiara un oggetto HttpClient, necessario per il metodo di accesso GetByteArrayAsync nel file ProcessURLAsync.

    • Il metodo crea e avvia tre attività di tipo Task, in cui TResult è un valore integer. Mentre ogni attività termina, DisplayResults visualizza l'URL dell'attività e la lunghezza dei contenuti scaricati. Poiché le attività vengono eseguite in modo asincrono, l'ordine in cui i risultati vengono visualizzati potrebbe differire dall'ordine in cui sono stati dichiarati.

    • Il metodo attende il completamento di ogni attività. Ogni operatore await o Await sospende l'esecuzione di CreateMultipleTasksAsync fino al completamento dell'attività attesa. L'operatore recupera inoltre il valore restituito dalla chiamata a ProcessURLAsync da ogni attività completata.

    • Quando le attività sono state completate e i valori integer sono stati recuperati, il metodo somma le lunghezze dei siti Web e visualizza il risultato.

    Copiare il seguente metodo e incollarlo nella propria soluzione.

    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. Premere il tasto F5 per eseguire il programma, quindi scegliere il pulsante Avvia.

    Eseguire il programma più volte per verificare che le tre attività non terminano sempre nello stesso ordine, inoltre l'ordine in cui vengono terminate non è necessariamente l'ordine in cui vengono create e messe in attesa.

Esempio

Il codice seguente include l'esempio 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);
        }
    }
}

Vedere anche

Attività

Procedura dettagliata: accesso al Web tramite Async e Await (C# e Visual Basic)

Procedura: estendere la procedura dettagliata asincrona tramite Task.WhenAll (C# e Visual Basic)

Concetti

Programmazione asincrona con Async e Await (C# e Visual Basic)