Esporta (0) Stampa
Espandi tutto
Il presente articolo è stato tradotto automaticamente. Passare il puntatore sulle frasi nell'articolo per visualizzare il testo originale. Ulteriori informazioni.
Traduzione
Originale
1 di 1 hanno valutato il contenuto utile: - Valuta questo argomento

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

È possibile evitare colli di bottiglia nelle prestazioni e migliorare la risposta generale dell'applicazione utilizzando la programmazione asincrona. Tuttavia, le tecniche tradizionali per la creazione di applicazioni asincrone possono essere complesse, pertanto può essere difficile scrivere, fare il debug e gestire queste applicazioni.

Visual Studio 2012 introduce un approccio semplificato, la programmazione asincrona, utilizzando il supporto asincrono in .NET Framework 4.5 e in Windows Runtime. Il compilatore esegue il lavoro complesso che lo sviluppatore era abituato a fare, e l'applicazione mantiene una struttura logica simile al codice sincrono. Di conseguenza, si ottengono tutti i vantaggi della programmazione asincrona con uno sforzo minimo.

Di seguito sono elencate le diverse sezioni di questo argomento.

In questo argomento viene fornita una panoramica di come e quando utilizzare la programmazione async e vengono forniti collegamenti per supportare gli argomenti contenenti informazioni dettagliate ed esempi.

L'asincronia è essenziale per le attività che potenzialmente bloccano, ad esempio quando l'applicazione accede al Web. L'accesso a una risorsa Web può essere talvolta lento o ritardato. Se tale attività viene bloccata in un processo sincrono, l'intera applicazione deve attendere. In un processo asincrono, l'applicazione può continuare con un altro lavoro che non dipende dalla risorsa Web finché non termina l'attività di blocco.

Nella tabella seguente sono mostrate le aree tipiche nelle quali la programmazione asincrona migliora la risposta. Le API elencate da .NET Framework 4.5 e Windows Runtime contengono metodi che supportano la programmazione async.

Area dell'applicazione

API di supporto che contengono metodi async

Accesso Web

HttpClient , Classe SyndicationClient

Utilizzo dei file

StorageFile, StreamWriter, StreamReader, XmlReader

Utilizzo delle immagini

MediaCapture BitmapEncoder, BitmapDecoder

Programmazione WCF

Operazioni sincrone e asincrone

L'asincronia è particolarmente importante per le applicazioni che accedono al thread dell'interfaccia utente poiché tutte le attività correlate all'interfaccia utente in genere condividono un thread. Se un processo è bloccato in un'applicazione sincrona, saranno tutti bloccati. L'applicazione non risponde e si potrebbe pensare che si sia verificato un errore mentre invece è solo in attesa.

Quando si utilizzano i metodi asincroni, l'applicazione continua a rispondere all'interfaccia utente. È possibile ridimensionare o ridurre ad icona una finestra, ad esempio, oppure è possibile chiudere l'applicazione se non si desidera attendere il completamento.

L'approccio basato su async aggiunge l'equivalente di una trasmissione automatica all'elenco di opzioni da cui è possibile scegliere quando si progettano operazioni asincrone. Ovvero si ottengono tutti i vantaggi della programmazione asincrona tradizionale ma con molto meno sforzo da parte dello sviluppatore.

Le parole chiave Async e Await in Visual Basic e le parole chiave async e await in C# sono il cuore della programmazione asincrona. Utilizzando queste due parole chiave, è possibile utilizzare le risorse di .NET Framework o di Windows Runtime per creare un metodo asincrono con la stessa facilità con cui è possibile creare un metodo sincrono. I metodi asincroni definiti mediante async e await sono denominati metodi async.

Nell'esempio seguente viene illustrato un metodo asincrono. Quasi tutti gli elementi del codice dovrebbe essere completamente noti all'utente. I commenti richiamano le funzionalità che si aggiungono per creare l'asincronia.

È possibile trovare il file di esempio completo alla fine di questo argomento e scaricare l'esempio da Esempio asincrono: Esempio da "Programmazione asincrona con async e await" .


// Three things to note in the signature:
//  - The method has an async modifier. 
//  - The return type is Task or Task<T>. (See "Return Types" section.)
//    Here, it is Task<int> because the return statement returns an integer.
//  - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync.
    //  - AccessTheWebAsync can't continue until getStringTask is complete.
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync.
    //  - Control resumes here when getStringTask is complete. 
    //  - The await operator then retrieves the string result from getStringTask.
    string urlContents = await getStringTask;

    // The return statement specifies an integer result.
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
    return urlContents.Length;
}


Se AccessTheWebAsync non ha alcuna operazione da eseguire tra la chiamata di GetStringAsync e il relativo completamento, è possibile semplificare il codice chiamando e attendendo la seguente istruzione singola.

string urlContents = await client.GetStringAsync();

Le seguenti caratteristiche riepilogano gli aspetti che rendono l'esempio precedente un metodo async.

  • La firma del metodo include un modificatore Async o async.

  • Il nome di un metodo async, per convenzione, termina con un suffisso "Async".

  • Il tipo di valore restituito è uno dei seguenti:

    • Task<TResult> se il metodo ha un'istruzione return in cui l'operando è di tipo TResult.

    • Task se il metodo non ha istruzione return o contiene un'istruzione return senza l'operando.

    • Void (un Sub in Visual Basic) se si sta scrivendo un gestore eventi asincrono.

    Per ulteriori informazioni, vedere la sezione "Tipi restituiti e parametri" più avanti in questo argomento.

  • Il metodo include in genere almeno un'espressione await, che contrassegna un punto in cui il metodo non può continuare fino a quando l'operazione asincrona attesa non sia completata. Nel frattempo, il metodo viene sospeso e il controllo ritorna al chiamante del metodo. Nella sezione successiva di questo argomento viene illustrato quello che accade in corrispondenza del punto di sospensione.

Nei metodi asincroni, utilizzare le parole chiave e i tipi forniti per indicare l'operazione che si desidera eseguire e il compilatore esegue il resto dell'operazione, inclusa la traccia di cosa deve verificarsi quando il controllo viene restituito a un punto di attesa in un metodo sospeso. Alcuni processi di routine, come cicli e gestione delle eccezioni, possono essere difficili da gestire nel codice asincrono tradizionale. In un metodo asincrono, scrivere questi elementi come in una soluzione sincrona e il problema viene risolto.

Per ulteriori informazioni sull'asincronia in versioni precedenti di .NET Framework, vedere Task Parallel Library e programmazione asincrona .NET Framework tradizionale.

La cosa più importante da capire nella programmazione asincrona è il modo in cui il flusso del controllo si sposta da un metodo all'altro. Nel diagramma seguente viene descritto il processo.

Tracciare un programma asincrono

I numeri nel diagramma corrispondono ai passaggi seguenti.

  1. Un gestore eventi chiama e attende il metodo async AccessTheWebAsync.

  2. AccessTheWebAsync crea un'istanza di HttpClient e chiama il metodo asincrono GetStringAsync per scaricare il contenuto di un sito Web come stringa.

  3. Si verifica un evento in GetStringAsync che ne sospende lo stato di avanzamento. Forse deve attendere il termine dello scaricamento di un sito Web o un'altra attività di blocco. Per evitare di bloccare le risorse, GetStringAsync restituisce il controllo al suo chiamante, AccessTheWebAsync.

    GetStringAsync restituisce Task<TResult> dove TResult è una stringa e AccessTheWebAsync assegna le attività alla variabile getStringTask. L'attività rappresenta il processo in corso per la chiamata a GetStringAsync, con l'impegno di produrre un valore stringa effettivo a completamento del lavoro.

  4. Poiché getStringTask non è stata ancora attesa, AccessTheWebAsync può continuare con altro lavoro che non dipende dal risultato finale ottenuto da GetStringAsync. Tale lavoro è rappresentato da una chiamata al metodo sincrono DoIndependentWork.

  5. DoIndependentWork è un metodo sincrono che esegue il proprio lavoro e lo restituisce al chiamante.

  6. AccessTheWebAsync ha esaurito il lavoro che può eseguire senza un risultato da getStringTask. AccessTheWebAsync desidera quindi calcolare e restituire la lunghezza della stringa scaricata, ma il metodo non può calcolare il valore finché quest'ultimo non contiene la stringa.

    Di conseguenza, AccessTheWebAsync utilizza un operatore await per sospendere lo stato di avanzamento e rendere il controllo al metodo che ha chiamato AccessTheWebAsync. AccessTheWebAsync restituisce Task(Of Integer) o Task<int> al chiamante. L'attività rappresenta l'intenzione di produrre un risultato Integer che è la lunghezza della stringa scaricata.

    Nota Nota

    Se GetStringAsync (e quindi getStringTask) viene completata prima che AccessTheWebAsync lo attenda, il controllo resta in AccessTheWebAsync. I costi per sospendere e tornare a AccessTheWebAsync sarebbero sprecati se il processo asincrono chiamato (getStringTask) fosse già completato e AccessTheWebSync non deve attendere il risultato finale.

    Nel chiamante (il gestore eventi in questo esempio), il criterio di processo continua. Il chiamante può eseguire altre attività che non dipendono dal risultato di AccessTheWebAsync prima di attendere tale risultato, oppure il chiamante può attendere immediatamente. Il gestore eventi è in attesa di AccessTheWebAsync e AccessTheWebAsync è in attesa di GetStringAsync.

  7. GetStringAsync completa e produce un risultato della stringa. Il risultato della stringa non viene restituito dalla chiamata a GetStringAsync nel modo prevedibile. Tenere presente che il metodo non ha restituito un'attività al passaggio 3). Invece il risultato della stringa viene memorizzato nell'attività che rappresenta il completamento del metodo, getStringTask. L'operatore await recupera il risultato da getStringTask. L'istruzione di assegnazione assegna il risultato recuperato a urlContents.

  8. Quando AccessTheWebAsync ha il risultato stringa, il metodo può calcolare la lunghezza della stringa. Il lavoro di AccessTheWebAsync è quindi completo e il gestore eventi in attesa può riprendere l'attività. Nell'esempio completo alla fine dell'argomento, è possibile confermare che il gestore eventi recupera e stampa il valore del risultato di lunghezza.

Se non si ha familiarità con la programmazione asincrona, prendere in considerazione la differenza tra il comportamento sincrono e asincrono. Viene restituito un metodo sincrono quando il lavoro è completato (passaggio 5), ma un metodo async restituisce un valore di attività quando il relativo lavoro viene sospeso (passaggi 3 e 6). Una volta che il metodo async completa l'operazione, l'attività viene contrassegnata come completata e il risultato, se disponibile, viene archiviato nell'attività.

Per ulteriori informazioni sul flusso di controllo, vedere Flusso di controllo in programmi asincroni (C# e Visual Basic).

Ci si potrebbe domandare dove sia possibile trovare metodi come GetStringAsync che supportano la programmazione async. Il .NET Framework 4.5 contiene molti membri che utilizzano async e await. È possibile riconoscere questi membri dal suffisso "Async" associato dal nome del membro e dal tipo restituito di Task o di Task<TResult>. Ad esempio, la classe System.IO.Stream contiene metodi come CopyToAsync, ReadAsync e WriteAsync insieme ai metodi sincroni CopyTo, Read e Write.

Windows Runtime contiene inoltre molti metodi utilizzabili con async e await nelle app di Windows Store. Per ulteriori informazioni e metodi di esempio, vedere Guida introduttiva: utilizzo dell'operatore await per la programmazione asincrona, Programmazione asincrona (app di Windows Store) e WhenAny: bridging tra .NET Framework e Windows Runtime (C# e Visual Basic).

I metodi asincroni vengono considerati operazioni non bloccanti. Un'espressione await in un metodo async non blocca il thread corrente quando l'attività attesa è in esecuzione. Al contrario, l'espressione registra il resto del metodo come continuazione e restituisce il controllo al chiamante del metodo asincrono.

Le parole chiave async e await non determinano la creazione di thread aggiuntivi. I metodi asincroni non richiedono multithreading perché non viene eseguito un metodo asincrono nel relativo thread. Il metodo viene eseguito nel contesto di sincronizzazione corrente e utilizza il tempo sul thread solo se il metodo è attivo. È possibile utilizzare Task.Run per spostare un lavoro associato alla CPU in un thread in background. Tuttavia un thread in background non fa nulla con un processo che attende solo che i risultati diventino disponibili.

L'approccio basato su async alla programmazione asincrona è quasi sempre preferibile agli approcci esistenti. In particolare, questo approccio è preferibile a BackgroundWorker per le operazioni associate a IO poiché il codice è più semplice e non è necessario proteggersi da race condition. Insieme a Task.Run, la programmazione asincrona è migliore di BackgroundWorker per le operazioni associate alla CPU perché la programmazione asincrona separa i dettagli di coordinamento per l'esecuzione del codice dal lavoro che Task.Run trasferisce al pool di thread.

Se si specifica che un metodo è asincrono utilizzando un modificatore Async o async, attivare le due funzionalità seguenti.

  • Il metodo async contrassegnato può utilizzare Await o await per definire i punti di sospensione. L'operatore await indica al compilatore che il metodo async non può continuare oltre un dato punto prima del completamento del processo asincrono in attesa. Nel frattempo, il controllo viene restituito al chiamante del metodo asincrono.

    La sospensione di un metodo async in corrispondenza di un'espressione await non costituisce l'uscita dal metodo e i blocchi finally non vengono eseguiti.

  • Il metodo async contrassegnato può essere atteso da metodi che lo chiamano.

Un metodo asincrono contiene in genere una o più occorrenze dell'operatore await, mentre l'assenza di espressioni await non provoca un errore del compilatore. Se un metodo async non utilizza un operatore await per contrassegnare un punto di sospensione, esso eseguirà un metodo sincrono, nonostante la presenza del modificatore async. Il compilatore genera un avviso per tali metodi.

Async , async, Await e await rappresentano parole chiave contestuali. Per ulteriori informazioni ed esempi, vedere i seguenti argomenti:

Nella programmazione di .NET Framework, un metodo asincrono in genere restituisce Task o Task<TResult>. In un metodo asincrono, un operatore await viene applicato a un'attività restituita da una chiamata a un altro metodo asincrono.

Specificare Task<TResult> come tipo restituito se il metodo contiene un'istruzione Return (Visual Basic) o return (C#) che specifica un operando di tipo TResult.

Utilizzare Task come tipo restituito se il metodo non include un'istruzione return o contiene un'istruzione return che non restituisce un operando.

Di seguito viene illustrato come dichiarare e chiamare un metodo che restituisce Task<TResult> o Task.

// Signature specifies Task<TResult>
async Task<int> TaskOfTResult_MethodAsync()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}

// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();


// Signature specifies Task
async Task Task_MethodAsync()
{
    // . . .
    // The method has no return statement.  
}

// Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync();
await returnedTask;
// or, in a single statement
await Task_MethodAsync();

Ogni attività restituita rappresenta il lavoro in corso. Un'attività include le informazioni sullo stato del processo asincrono e, infine, il risultato finale del processo o l'eccezione che il processo genera se non viene completato.

Un metodo async può essere anche un metodo Sub (Visual Basic) o avere un tipo restituito void (C#). Il tipo restituito viene utilizzato principalmente per definire i gestori eventi, dove un tipo restituito void è necessario. I gestori eventi Async fungono spesso da punto di partenza per i programmi async.

Un metodo async che è una routine Sub o con un tipo restituito void non può essere atteso e il chiamante di un metodo che restituisce void non può rilevare eventuali eccezioni che il metodo genera.

Un metodo asincrono non può dichiarare i parametri ByRef in Visual Basic o i parametri ref o out in C#, ma il metodo può chiamare i metodi che presentano tali parametri.

Per ulteriori informazioni ed esempi, vedere Tipi restituiti asincroni (C# e Visual Basic). Per ulteriori informazioni su come intercettare eccezioni nei metodi asincroni, vedere try-catch (Riferimenti per C#) o Istruzione Try...Catch...Finally (Visual Basic).

Le API asincrone nella programmazione Windows Runtime presentano uno dei seguenti tipi restituiti, che sono simili alle attività:

Per ulteriori informazioni e un esempio, vedere Guida introduttiva: utilizzo dell'operatore await per la programmazione asincrona.

Per convenzione, aggiungere il suffisso "Async" ai nomi dei metodi che presentano un modificatore Async o async.

È possibile ignorare la convenzione dove un evento, una classe di base o un contratto dell'interfaccia suggeriscono un nome diverso. Ad esempio, non è necessario rinominare i gestori di eventi comuni, come Button1_Click.

Titolo

Descrizione

Esempio

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

Mostra come convertire una soluzione WPF sincrona a una soluzione WPF asincrona. L'applicazione scarica una serie di siti Web.

Esempio asincrono: Accesso alla procedura dettagliata Web (C# e Visual Basic)

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

Aggiunge Task.WhenAll alla procedura dettagliata precedente. L'utilizzo di WhenAll consente di avviare tutti i download contemporaneamente.

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

Viene illustrato come avviare contemporaneamente diverse attività.

Esempio asincrono: Esecuzione di più richieste Web in parallelo (C# e Visual Basic)

Tipi restituiti asincroni (C# e Visual Basic)

Vengono illustrati i tipi che i metodi asincroni possono restituire e quando ogni tipo è appropriato.

Flusso di controllo in programmi asincroni (C# e Visual Basic)

Traccia in dettaglio il flusso di controllo con una successione di espressioni await in un programma asincrono.

Esempio asincrono: Flusso di controllo nei programmi asincroni (C# e Visual Basic)

Ottimizzazione dell'applicazione Async (C# e Visual Basic)

Mostra come aggiungere la seguente funzionalità alla soluzione async:

Esempio asincrono: Ottimizzazione dell'applicazione (C# e Visual Basic)

Gestione della reentrancy nelle applicazioni asincrone (C# e Visual Basic)

Viene illustrato come gestire i casi in cui un'operazione asincrona attiva viene riavviata in esecuzione.

WhenAny: bridging tra .NET Framework e Windows Runtime (C# e Visual Basic)

Viene illustrato come integrare i tipi di attività in .NET Framework e IAsyncOperations in Windows Runtime in modo da utilizzare WhenAny con un metodo Windows Runtime.

Esempio asincrono: Bridging tra .NET e Windows Runtime (AsTask e WhenAny)

Annullamento asincrono: bridging tra .NET Framework e Windows Runtime (C# e Visual Basic)

Viene illustrato come integrare i tipi di attività in .NET Framework e IAsyncOperations in Windows Runtime in modo da utilizzare CancellationTokenSource con un metodo Windows Runtime.

Esempio asincrono: Bridging tra .NET e Windows Runtime (AsTask & annullamento)

Utilizzo della funzionalità Async per l'accesso ai file (C# e Visual Basic)

Vengono elencati e illustrati i vantaggi dell'utilizzo di async e await per accedere ai file.

Procedura dettagliata: utilizzo del debugger con metodi Async

Viene illustrato il flusso di controllo in un'istruzione await e il comportamento dei comandi Esegui istruzione, Esegui istruzione/routinee Esci da istruzione/routine nei metodi asincroni.

Modello asincrono basato su attività (TAP)

Descrive un nuovo modello per l'asincronia in .NET Framework. Il modello è basato sui tipi Task<TResult> e Task.

Guida rapida: chiamata ad API asincrone in C# o Visual Basic

Mostra come utilizzare async e await in un'applicazione Windows Store.

Programmazione asincrona (applicazioni Windows Store)

Viene fornita una descrizione generale della programmazione asincrona nel Windows Runtime.

Video Async su Channel 9

Vengono forniti collegamenti a una serie di video sulla programmazione asincrona.

Il codice seguente rappresenta il file MainWindow.xaml.vb o MainWindow.xaml.cs dall'applicazione Windows Presentation Foundation (WPF) discussa in questo argomento. È possibile scaricare l'esempio da Esempio asincrono: Esempio da "Programmazione asincrona con async e await".


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 a using directive and a reference for System.Net.Http;
using System.Net.Http;

namespace AsyncFirstExample
{
    public partial class MainWindow : Window
    {
        // Mark the event handler with async so you can use await in it.
        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // Call and await separately.
            //Task<int> getLengthTask = AccessTheWebAsync();
            //// You can do independent work here.
            //int contentLength = await getLengthTask;

            int contentLength = await AccessTheWebAsync();

            resultsTextBox.Text +=
                String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
        }


        // Three things to note in the signature:
        //  - The method has an async modifier. 
        //  - The return type is Task or Task<T>. (See "Return Types" section.)
        //    Here, it is Task<int> because the return statement returns an integer.
        //  - The method name ends in "Async."
        async Task<int> AccessTheWebAsync()
        { 
            // You need to add a reference to System.Net.Http to declare client.
            HttpClient client = new HttpClient();

            // GetStringAsync returns a Task<string>. That means that when you await the
            // task you'll get a string (urlContents).
            Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

            // You can do work here that doesn't rely on the string from GetStringAsync.
            DoIndependentWork();

            // The await operator suspends AccessTheWebAsync.
            //  - AccessTheWebAsync can't continue until getStringTask is complete.
            //  - Meanwhile, control returns to the caller of AccessTheWebAsync.
            //  - Control resumes here when getStringTask is complete. 
            //  - The await operator then retrieves the string result from getStringTask.
            string urlContents = await getStringTask;

            // The return statement specifies an integer result.
            // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
            return urlContents.Length;
        }


        void DoIndependentWork()
        {
            resultsTextBox.Text += "Working . . . . . . .\r\n";
        }
    }
}

// Sample Output:

// Working . . . . . . .

// Length of the downloaded string: 41564.


Il documento è risultato utile?
(1500 caratteri rimanenti)
Grazie per i commenti inviati.

Aggiunte alla community

AGGIUNGI
Microsoft sta conducendo un sondaggio in linea per comprendere l'opinione degli utenti in merito al sito Web di MSDN. Se si sceglie di partecipare, quando si lascia il sito Web di MSDN verrà visualizzato il sondaggio in linea.

Si desidera partecipare?
Mostra:
© 2014 Microsoft. Tutti i diritti riservati.