Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
È possibile evitare colli di bottiglia delle prestazioni e migliorare la velocità di risposta complessiva dell'applicazione usando la programmazione asincrona. Tuttavia, le tecniche tradizionali per la scrittura di applicazioni asincrone possono essere complesse, rendendo difficile scrivere, eseguire il debug e gestire.
Visual Studio 2012 ha introdotto un approccio semplificato, la programmazione asincrona, che sfrutta il supporto asincrono in .NET Framework 4.5 e versioni successive, nonché in Windows Runtime. Il compilatore esegue il lavoro difficile usato dallo sviluppatore e l'applicazione mantiene una struttura logica simile a codice sincrono. Di conseguenza, si ottengono tutti i vantaggi della programmazione asincrona con una frazione dello sforzo.
Questo argomento offre una panoramica di quando e come usare la programmazione asincrona e include collegamenti a argomenti di supporto che contengono dettagli ed esempi.
Async migliora la velocità di risposta
Asincronia è essenziale per le attività potenzialmente bloccabili, ad esempio quando l'applicazione accede al Web. L'accesso a una risorsa Web a volte è lento o ritardato. Se tale attività viene bloccata all'interno di un processo sincrono, l'intera applicazione deve attendere. In un processo asincrono, l'applicazione può continuare con altre operazioni che non dipendono dalla risorsa Web fino al termine dell'attività di blocco potenziale.
La tabella seguente illustra le aree tipiche in cui la programmazione asincrona migliora la velocità di risposta. Le API elencate da .NET Framework 4.5 e Windows Runtime contengono metodi che supportano la programmazione asincrona.
Area dell'applicazione | Supporto di API che contengono metodi asincroni |
---|---|
Accesso Web | HttpClient, SyndicationClient |
Uso dei file | StorageFile, StreamWriter, StreamReaderXmlReader |
Uso delle immagini | MediaCapture, BitmapEncoder, BitmapDecoder |
Programmazione WCF | operazioni sincrone e asincrone |
L'asincronia si dimostra particolarmente utile per le applicazioni che accedono al thread dell'interfaccia utente perché tutte le attività relative all'interfaccia utente condividono in genere un thread. Se un processo viene bloccato in un'applicazione sincrona, tutti vengono bloccati. L'applicazione smette di rispondere e si potrebbe concludere che non è riuscita quando è invece in attesa.
Quando si usano metodi asincroni, l'applicazione continua a rispondere all'interfaccia utente. È possibile ridimensionare o ridurre al minimo una finestra, ad esempio, oppure chiudere l'applicazione se non si vuole attendere il completamento.
L'approccio asincrono aggiunge l'equivalente di una trasmissione automatica all'elenco di opzioni tra cui è possibile scegliere durante la progettazione di operazioni asincrone. Ciò significa che si ottengono tutti i vantaggi della programmazione asincrona tradizionale, ma con molto meno impegno da parte dello sviluppatore.
I metodi asincroni sono più facili da scrivere
Le parole chiave Async e Await in Visual Basic sono il fulcro della programmazione asincrona. Usando queste due parole chiave, è possibile usare le risorse in .NET Framework o Windows Runtime per creare un metodo asincrono quasi facilmente quando si crea un metodo sincrono. I metodi asincroni definiti tramite Async
e Await
vengono definiti metodi asincroni.
Nell'esempio seguente viene illustrato un metodo asincrono. Quasi tutto il codice dovrebbe avere un aspetto completamente familiare. I commenti evidenziano le funzionalità che aggiungi per creare l'asincronia.
È possibile trovare un file di esempio completo di Windows Presentation Foundation (WPF) alla fine di questo argomento ed è possibile scaricare l'esempio da Async Sample: Example from "Asynchronous Programming with Async and Await" (Programmazione asincrona con Async e Await).
' Three things to note about writing an Async Function:
' - The function has an Async modifier.
' - Its return type is Task or Task(Of T). (See "Return Types" section.)
' - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
Using client As New HttpClient()
' Call and await separately.
' - AccessTheWebAsync can do other things while GetStringAsync is also running.
' - getStringTask stores the task we get from the call to GetStringAsync.
' - Task(Of String) means it is a task which returns a String when it is done.
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://learn.microsoft.com/dotnet")
' You can do other work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork()
' The Await operator suspends AccessTheWebAsync.
' - AccessTheWebAsync does not 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.
Dim urlContents As String = Await getStringTask
' The Return statement specifies an Integer result.
' A method which awaits AccessTheWebAsync receives the Length value.
Return urlContents.Length
End Using
End Function
Se AccessTheWebAsync
non ha alcun lavoro che può eseguire tra la chiamata GetStringAsync
e l'attesa del completamento, è possibile semplificare il codice chiamando e attendendo nella singola istruzione seguente.
Dim urlContents As String = Await client.GetStringAsync()
Le caratteristiche seguenti riepilogano ciò che rende l'esempio precedente un metodo asincrono:
La firma del metodo include un modificatore
Async
.Il nome di un metodo asincrono, per convenzione, termina con un suffisso "Async".
Il tipo restituito è uno dei tipi seguenti:
- Task(Of TResult) se il metodo dispone di un'istruzione return in cui l'operando ha il tipo TResult.
- Task se il metodo non ha un'istruzione return o ha un'istruzione return senza operando.
- Sub se si sta scrivendo un gestore eventi asincrono.
Per altre informazioni, vedere "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 al completamento dell'operazione asincrona attesa. Nel frattempo, il metodo viene sospeso e il controllo torna al chiamante del metodo. La sezione successiva di questo argomento illustra cosa accade al punto di sospensione.
Nei metodi asincroni si usano le parole chiave e i tipi forniti per indicare le operazioni da eseguire e il compilatore esegue il resto, incluso tenere traccia di ciò che deve accadere quando il controllo torna a un punto await in un metodo sospeso. Alcuni processi di routine, ad esempio cicli e gestione delle eccezioni, possono essere difficili da gestire nel codice asincrono tradizionale. In un metodo asincrono questi elementi vengono scritti in modo analogo a quanto si farebbe in una soluzione sincrona e il problema viene risolto.
Per altre informazioni sull'asincronia nelle versioni precedenti di .NET Framework, vedere TPL e Programmazione asincrona tradizionale di .NET Framework.
Cosa accade in un metodo asincrono
La cosa più importante da comprendere nella programmazione asincrona è il modo in cui il flusso di controllo passa dal metodo al metodo. Il diagramma seguente illustra il processo:
I numeri nel diagramma corrispondono ai passaggi seguenti:
Un gestore eventi chiama e attende il
AccessTheWebAsync
metodo asincrono.AccessTheWebAsync
crea un'istanza di HttpClient e chiama il metodo asincrono GetStringAsync per scaricare il contenuto di un sito Web come stringa.Qualcosa accade in
GetStringAsync
che sospende il suo progresso. Forse deve attendere il download di un sito Web o un'altra attività di blocco. Per evitare di bloccare le risorse,GetStringAsync
restituisce il controllo al chiamante,AccessTheWebAsync
.GetStringAsync
restituisce un oggetto Task(Of TResult) in cui TResult è una stringa eAccessTheWebAsync
assegna l'attività allagetStringTask
variabile. L'attività rappresenta il processo in corso per la chiamata aGetStringAsync
, con l'impegno di produrre un valore stringa reale al termine del lavoro.Poiché
getStringTask
non è stato ancora atteso,AccessTheWebAsync
può continuare con altri lavori che non dipendono dal risultato finale diGetStringAsync
. Tale lavoro è rappresentato da una chiamata al metodo sincronoDoIndependentWork
.DoIndependentWork
è un metodo sincrono che esegue il lavoro e restituisce al chiamante.AccessTheWebAsync
ha esaurito il lavoro che può eseguire senza un risultato dagetStringTask
.AccessTheWebAsync
successivamente vuole calcolare e restituire la lunghezza della stringa scaricata, ma il metodo non può calcolare tale valore finché il metodo non ha la stringa.Pertanto,
AccessTheWebAsync
usa un operatore await per sospendere lo stato di avanzamento e restituire il controllo al metodo che ha chiamatoAccessTheWebAsync
.AccessTheWebAsync
restituisce unTask(Of Integer)
al chiamante. L'attività rappresenta una promessa per produrre un risultato integer che corrisponde alla lunghezza della stringa scaricata.Annotazioni
Se
GetStringAsync
(e quindigetStringTask
) viene completato prima cheAccessTheWebAsync
lo attenda, il controllo rimane inAccessTheWebAsync
. La spesa per la sospensione e quindi il ritorno aAccessTheWebAsync
sarebbe sprecato se il processo asincrono chiamato (getStringTask
) è già stato completato e AccessTheWebSync non deve attendere il risultato finale.All'interno del chiamante (gestore eventi in questo esempio), il modello di elaborazione continua. Il chiamante potrebbe eseguire altre operazioni che non dipendono dal risultato di
AccessTheWebAsync
prima di attendere tale risultato oppure il chiamante potrebbe attendere immediatamente. Il gestore eventi è in attesa diAccessTheWebAsync
eAccessTheWebAsync
è in attesa diGetStringAsync
.GetStringAsync
completa e produce un risultato sotto forma di stringa. Il risultato della stringa non viene restituito dalla chiamata aGetStringAsync
nel modo previsto. Tenere presente che il metodo ha già restituito un'attività nel passaggio 3. Il risultato della stringa viene invece archiviato nell'attività che rappresenta il completamento del metodogetStringTask
. L'operatore await recupera il risultato dagetStringTask
. L'istruzione di assegnazione assegna il risultato recuperato aurlContents
.Quando
AccessTheWebAsync
ha il risultato della stringa, il metodo può calcolare la lunghezza della stringa. Il lavoro diAccessTheWebAsync
viene quindi completato e il gestore di eventi in attesa può riprendere. Nell'esempio completo alla fine dell'argomento è possibile verificare che il gestore eventi recuperi e stampi il valore del risultato della lunghezza.
Se sei nuovo alla programmazione asincrona, prenditi un momento per considerare la differenza tra il comportamento sincrono e quello asincrono. Un metodo sincrono restituisce quando il lavoro è completo (passaggio 5), ma un metodo asincrono restituisce un valore di attività quando il lavoro viene sospeso (passaggi 3 e 6). Quando il metodo asincrono completa il proprio lavoro, l'attività viene contrassegnata come completata e il risultato, se presente, viene archiviato nell'attività.
Per altre informazioni sul flusso di controllo, vedere Flusso di controllo in Programmi asincroni (Visual Basic).For more information about control flow, see Control Flow in Async Programs (Visual Basic).
Metodi asincroni dell'API
Ci si potrebbe chiedere dove trovare metodi come GetStringAsync
che supportano la programmazione asincrona. .NET Framework 4.5 o versione successiva contiene molti membri che funzionano con Async
e Await
. È possibile riconoscere questi membri in base al suffisso "Async" associato al nome del membro e a un tipo restituito di Task o Task(Of TResult). Ad esempio, la classe System.IO.Stream
contiene metodi come CopyToAsync, ReadAsynce WriteAsync insieme ai metodi sincroni CopyTo, Reade Write.
Windows Runtime contiene anche molti metodi che è possibile usare con Async
e Await
nelle app di Windows. Per altre informazioni e metodi di esempio, vedere Chiamare API asincrone in C# o Visual Basic, Programmazione asincrona (app di Windows Runtime) e WhenAny: Bridging tra .NET Framework e Windows Runtime.
Discussioni
I metodi asincroni devono essere operazioni non bloccabili. Un'espressione Await
in un metodo asincrono non blocca il thread corrente mentre l'attività attesa è in esecuzione. Invece, 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 causano la creazione di thread aggiuntivi. I metodi asincroni non richiedono il multithreading perché un metodo asincrono non viene eseguito nel proprio thread. Il metodo viene eseguito nel contesto di sincronizzazione corrente e usa l'ora nel thread solo quando il metodo è attivo. È possibile usare Task.Run per spostare il lavoro associato alla CPU in un thread in background, ma un thread in background non è utile per un processo in attesa che i risultati diventino disponibili.
L'approccio asincrono alla programmazione asincrona è preferibile agli approcci esistenti in quasi ogni caso. In particolare, questo approccio è migliore rispetto a BackgroundWorker per le operazioni I/O, perché il codice è più semplice e non è necessario proteggersi dalle condizioni di gara. In combinazione con Task.Run, la programmazione asincrona è migliore rispetto BackgroundWorker alle operazioni associate alla CPU perché la programmazione asincrona separa i dettagli di coordinamento dell'esecuzione del codice dal lavoro che Task.Run
trasferisce al pool di thread.
Async e Await
Se si specifica che un metodo è asincrono usando un modificatore asincrono , abilitare le due funzionalità seguenti.
Il metodo asincrono contrassegnato può usare Await per designare i punti di sospensione. L'operatore await indica al compilatore che il metodo asincrono non può continuare oltre quel punto fino al completamento del processo asincrono atteso. Nel frattempo, il controllo torna al chiamante del metodo asincrono.
La sospensione di un metodo asincrono in un'espressione
Await
non costituisce un'uscita dal metodo, e i blocchiFinally
non vengono eseguiti.Il metodo asincrono contrassegnato può essere atteso dai metodi che lo chiamano.
Un metodo asincrono contiene in genere una o più occorrenze di un operatore Await
, ma l'assenza di espressioni Await
non causa un errore del compilatore. Se un metodo asincrono non usa un operatore Await
per contrassegnare un punto di sospensione, il metodo viene eseguito come metodo sincrono, nonostante il modificatore Async
. Il compilatore genera un avviso per tali metodi.
Async
e Await
sono parole chiave contestuali. Per altre informazioni ed esempi, vedere gli argomenti seguenti:
Tipi e parametri restituiti
Nella programmazione di .NET Framework, un metodo asincrono restituisce in genere un Task o un Task(Of TResult). All'interno di un metodo asincrono, un operatore Await
viene applicato a un'attività restituita da una chiamata a un altro metodo asincrono.
Specificare Task(Of TResult) come tipo restituito se il metodo contiene un'istruzione Return che specifica un operando di tipo TResult
.
Si usa Task
come tipo restituito se il metodo non ha un'istruzione return o ha un'istruzione return che non restituisce un operando.
Nell'esempio seguente viene illustrato come dichiarare e chiamare un metodo che restituisce un oggetto Task(Of TResult) o un oggetto Task:
' Signature specifies Task(Of Integer)
Async Function TaskOfTResult_MethodAsync() As Task(Of Integer)
Dim hours As Integer
' . . .
' Return statement specifies an integer result.
Return hours
End Function
' Calls to TaskOfTResult_MethodAsync
Dim returnedTaskTResult As Task(Of Integer) = TaskOfTResult_MethodAsync()
Dim intResult As Integer = Await returnedTaskTResult
' or, in a single statement
Dim intResult As Integer = Await TaskOfTResult_MethodAsync()
' Signature specifies Task
Async Function Task_MethodAsync() As Task
' . . .
' The method has no return statement.
End Function
' 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à incapsula informazioni sullo stato del processo asincrono e, eventualmente, il risultato finale del processo o l'eccezione che il processo solleva se non riesce.
Un metodo asincrono può anche essere un Sub
metodo . Questo tipo di restituzione viene utilizzato principalmente per definire i gestori di eventi, in cui è necessario specificare un tipo di ritorno. I gestori eventi asincroni spesso fungono da punto di partenza per i programmi asincroni.
Non è possibile attendere un metodo asincrono che rappresenta una Sub
routine e il chiamante non può intercettare eccezioni generate dal metodo.
Un metodo asincrono non può dichiarare parametri ByRef , ma il metodo può chiamare metodi con tali parametri.
Per altre informazioni ed esempi, vedere Tipi restituiti asincroni (Visual Basic).For more information and examples, see Async Return Types (Visual Basic). Per ulteriori informazioni su come intercettare le eccezioni nei metodi asincroni, vedere Try...Catch...Finally Statement.
Le API asincrone nella programmazione di Windows Runtime hanno uno dei seguenti tipi di ritorno, che sono simili ai compiti:
- IAsyncOperation(Of TResult), che corrisponde a Task(Of TResult)
- IAsyncAction, che corrisponde a Task
- IAsyncActionWithProgress(Of TProgress)
- IAsyncOperationWithProgress(Of TResult, TProgress)
Per altre informazioni e un esempio, vedere Chiamare API asincrone in C# o Visual Basic.
Convenzione di denominazione
Per convenzione, aggiungere "Async" ai nomi dei metodi che dispongono di un Async
modificatore.
È possibile ignorare la convenzione in cui un evento, una classe di base o un contratto di interfaccia suggerisce un nome diverso. Ad esempio, non è consigliabile rinominare gestori eventi comuni, ad esempio Button1_Click
.
Argomenti ed esempi correlati (Visual Studio)
Titolo | Descrizione | Esempio |
---|---|---|
Procedura dettagliata: Accesso al Web tramite Async e Await (Visual Basic) | Illustra come convertire una soluzione WPF sincrona in una soluzione WPF asincrona. L'applicazione scarica una serie di siti Web. | Esempio asincrono: programmazione asincrona con Async e Await (Visual Basic) |
Procedura: Estendere la procedura dettagliata asincrona usando Task.WhenAll (Visual Basic) | Aggiunge Task.WhenAll alla procedura dettagliata precedente. L'uso di WhenAll avvia tutti i download contemporaneamente. |
|
Procedura: Eseguire più richieste Web in parallelo tramite async e await (Visual Basic) | Illustra come avviare più attività contemporaneamente. | Esempio asincrono: Effettuare più richieste Web in parallelo |
Tipi restituiti asincroni (Visual Basic) | Illustra i tipi che i metodi asincroni possono restituire e spiegano quando ogni tipo è appropriato. | |
Flusso di controllo nei programmi asincroni (Visual Basic) | Traccia in dettaglio il flusso di controllo attraverso una serie di espressioni 'await' in un programma asincrono. | Esempio asincrono: Flusso di controllo nei programmi asincroni |
Fine-Tuning La Tua Applicazione Asincrona (Visual Basic) | Illustra come aggiungere la funzionalità seguente alla soluzione asincrona: - Annullare un'attività asincrona o un elenco di attività (Visual Basic) - Annullare attività asincrone dopo un periodo di tempo (Visual Basic) - Annullare le attività asincrone rimanenti dopo il completamento di un'attività (Visual Basic) - Avviare più attività asincrone ed elaborarle al termine (Visual Basic) |
Esempio asincrono: Ottimizzazione dell'applicazione |
Gestione della rientranza nelle app asincrone (Visual Basic) | Illustra come gestire i casi in cui un'operazione asincrona attiva viene riavviata mentre è in corso. | |
WhenAny: Connessione tra .NET Framework e Windows Runtime | Illustra come eseguire il bridge tra i tipi di attività in .NET Framework e IAsyncOperations in Windows Runtime in modo che sia possibile usare WhenAny con un metodo Windows Runtime. | Esempio asincrono: Collegamento tra .NET e Windows Runtime (AsTask e WhenAny) |
Annullamento asincrono: Collegamento tra .NET Framework e Windows Runtime | Illustra come eseguire il bridge tra i tipi di attività in .NET Framework e IAsyncOperations in Windows Runtime in modo che sia possibile usare CancellationTokenSource con un metodo Windows Runtime. | |
Uso di Async per l'accesso ai file (Visual Basic) | Elenca e illustra i vantaggi dell'uso di async e await per accedere ai file. | |
Modello asincrono basato su attività (TAP) | Descrive un nuovo modello per asincronia in .NET Framework. Il modello è basato sui tipi Task e Task(Of TResult). |
Esempio completo
Il codice seguente è il file MainWindow.xaml.vb dell'applicazione Windows Presentation Foundation (WPF) descritta in questo argomento. È possibile scaricare l'esempio da Async Sample: Example from "Asynchronous Programming with Async and Await" (Programmazione asincrona con Async e Await).
Imports System.Net.Http
' Example that demonstrates Asynchronous Programming with Async and Await.
' It uses HttpClient.GetStringAsync to download the contents of a website.
' Sample Output:
' Working . . . . . . .
'
' Length of the downloaded string: 39678.
Class MainWindow
' Mark the event handler with Async so you can use Await in it.
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
' Call and await immediately.
' StartButton_Click suspends until AccessTheWebAsync is done.
Dim contentLength As Integer = Await AccessTheWebAsync()
ResultsTextBox.Text &= $"{vbCrLf}Length of the downloaded string: {contentLength}.{vbCrLf}"
End Sub
' Three things to note about writing an Async Function:
' - The function has an Async modifier.
' - Its return type is Task or Task(Of T). (See "Return Types" section.)
' - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
Using client As New HttpClient()
' Call and await separately.
' - AccessTheWebAsync can do other things while GetStringAsync is also running.
' - getStringTask stores the task we get from the call to GetStringAsync.
' - Task(Of String) means it is a task which returns a String when it is done.
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://learn.microsoft.com/dotnet")
' You can do other work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork()
' The Await operator suspends AccessTheWebAsync.
' - AccessTheWebAsync does not 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.
Dim urlContents As String = Await getStringTask
' The Return statement specifies an Integer result.
' A method which awaits AccessTheWebAsync receives the Length value.
Return urlContents.Length
End Using
End Function
Sub DoIndependentWork()
ResultsTextBox.Text &= $"Working . . . . . . .{vbCrLf}"
End Sub
End Class