Flusso di controllo in programmi asincroni (Visual Basic)
Le parole chiave Async
e Await
consentono di scrivere e gestire più facilmente i programmi asincroni. Tuttavia, i risultati potrebbero creare perplessità se non si conosce il funzionamento del programma. Questo argomento descrive il flusso di controllo attraverso un programma asincrono semplice per indicare quando il controllo si sposta da un metodo a un altro e quali informazioni vengono trasferite ogni volta.
Nota
Le parole chiave Async
e Await
sono state introdotte in Visual Studio 2012.
In generale, si contrassegnano i metodi che contengono codice asincrono con il modificatore Async. In un metodo contrassegnato con un modificatore async è possibile usare un operatore Await (Visual Basic) per specificare dove il metodo viene sospeso in attesa del completamento di un processo asincrono chiamato. Per altre informazioni, vedere Programmazione asincrona con Async e Await (Visual Basic).
L'esempio seguente usa i metodi asincroni per scaricare come stringa il contenuto di un sito Web specificato e per visualizzare la lunghezza della stringa. L'esempio contiene i due metodi seguenti.
startButton_Click
, che chiamaAccessTheWebAsync
e visualizza il risultato.AccessTheWebAsync
, che scarica il contenuto di un sito Web come stringa e restituisce la lunghezza della stringa.AccessTheWebAsync
usa un metodo HttpClient asincrono, ovvero GetStringAsync(String), per scaricare il contenuto.
In corrispondenza dei punti strategici del programma sono visualizzate righe numerate che consentono di comprendere come viene eseguito il programma e spiegano che cosa accade in ogni punto contrassegnato. Le righe sono evidenziate con etichette numerate da "ONE" a "SIX." Le etichette rappresentano l'ordine in cui il programma raggiunge queste righe di codice.
Il codice seguente rappresenta una struttura del programma.
Class MainWindow
Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
' ONE
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
' FOUR
Dim contentLength As Integer = Await getLengthTask
' SIX
ResultsTextBox.Text &=
vbCrLf & $"Length of the downloaded string: {contentLength}." & vbCrLf
End Sub
Async Function AccessTheWebAsync() As Task(Of Integer)
' TWO
Dim client As HttpClient = New HttpClient()
Dim getStringTask As Task(Of String) =
client.GetStringAsync("https://learn.microsoft.com")
' THREE
Dim urlContents As String = Await getStringTask
' FIVE
Return urlContents.Length
End Function
End Class
Ognuna delle posizioni con etichetta da "ONE" a "SIX" visualizza informazioni sullo stato corrente del programma. Viene prodotto l'output seguente:
ONE: Entering startButton_Click.
Calling AccessTheWebAsync.
TWO: Entering AccessTheWebAsync.
Calling HttpClient.GetStringAsync.
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Length of the downloaded string: 33946.
Impostare il programma
È possibile scaricare il codice usato in questo argomento da MSDN oppure crearlo manualmente.
Nota
Per eseguire l'esempio, è necessario che nel computer siano installati Visual Studio 2012 o versioni successive e .NET Framework 4.5 o versioni successive.
Scaricare il programma
È possibile scaricare l'applicazione di questo argomento da Async Sample: Control Flow in Async Programs (Esempio di attività asincrona: flusso di controllo in programmi asincroni). I passaggi seguenti consentono di aprire ed eseguire il programma.
Decomprimere il file scaricato e quindi avviare Visual Studio.
Nella barra dei menu scegliere File, Apri, Progetto/Soluzione.
Passare alla cartella che contiene il codice di esempio decompresso, aprire il file della soluzione (SLN) e quindi premere F5 per compilare ed eseguire il progetto.
Compilare il programma autonomamente
Il seguente progetto Windows Presentation Foundation (WPF) contiene gli esempi di codice per questo argomento.
Per eseguire il progetto, effettuare i passaggi seguenti:
Avviare Visual Studio.
Nella barra dei menu scegliere File, Nuovo, Progetto.
Verrà visualizzata la finestra di dialogo Nuovo progetto .
Nel riquadro Modelli installati, scegliere Visual Basic e quindi scegliere Applicazione WPF nell'elenco dei tipi di progetto.
Immettere
AsyncTracer
come nome del progetto e scegliere OK.Il nuovo progetto verrà visualizzato in Esplora soluzioni.
Nell'Editor di codice di Visual Studio scegliere la scheda MainWindow.xaml .
Se la scheda non è visibile, aprire il menu di scelta rapida per MainWindow.xaml in Esplora soluzioni e scegliere Visualizza codice.
Nella visualizzazione XAML di MainWindow.xaml sostituire il codice con quello riportato di seguito.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow" Title="Control Flow Trace" Height="350" Width="525"> <Grid> <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top" Width="75"/> <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="510" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" d:LayoutOverrides="HorizontalMargin"/> </Grid> </Window>
Nella visualizzazione Progettazione di MainWindow.xaml viene visualizzata una finestra semplice contenente una casella di testo e un pulsante.
Aggiunge un riferimento a System.Net.Http.
In Esplora soluzioni aprire il menu di scelta rapida per MainWindow.xaml.vb e quindi scegliere Visualizza codice.
Sostituire il codice in MainWindow.xaml.vb con quello riportato di seguito.
' Add an Imports statement and a reference for System.Net.Http. Imports System.Net.Http Class MainWindow Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click ' The display lines in the example lead you through the control shifts. ResultsTextBox.Text &= "ONE: Entering StartButton_Click." & vbCrLf & " Calling AccessTheWebAsync." & vbCrLf Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync() ResultsTextBox.Text &= vbCrLf & "FOUR: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is started." & vbCrLf & " About to await getLengthTask -- no caller to return to." & vbCrLf Dim contentLength As Integer = Await getLengthTask ResultsTextBox.Text &= vbCrLf & "SIX: Back in StartButton_Click." & vbCrLf & " Task getLengthTask is finished." & vbCrLf & " Result from AccessTheWebAsync is stored in contentLength." & vbCrLf & " About to display contentLength and exit." & vbCrLf ResultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength) End Sub Async Function AccessTheWebAsync() As Task(Of Integer) ResultsTextBox.Text &= vbCrLf & "TWO: Entering AccessTheWebAsync." ' Declare an HttpClient object. Dim client As HttpClient = New HttpClient() ResultsTextBox.Text &= vbCrLf & " Calling HttpClient.GetStringAsync." & vbCrLf ' GetStringAsync returns a Task(Of String). Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com") ResultsTextBox.Text &= vbCrLf & "THREE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is started." ' AccessTheWebAsync can continue to work until getStringTask is awaited. ResultsTextBox.Text &= vbCrLf & " About to await getStringTask & return a Task(Of Integer) to StartButton_Click." & vbCrLf ' Retrieve the website contents when task is complete. Dim urlContents As String = Await getStringTask ResultsTextBox.Text &= vbCrLf & "FIVE: Back in AccessTheWebAsync." & vbCrLf & " Task getStringTask is complete." & vbCrLf & " Processing the return statement." & vbCrLf & " Exiting from AccessTheWebAsync." & vbCrLf Return urlContents.Length End Function End Class
Premere il tasto F5 per eseguire il programma e quindi scegliere il pulsante Start .
Dovrebbe venire visualizzato l'output seguente:
ONE: Entering startButton_Click. Calling AccessTheWebAsync. TWO: Entering AccessTheWebAsync. Calling HttpClient.GetStringAsync. THREE: Back in AccessTheWebAsync. Task getStringTask is started. About to await getStringTask & return a Task<int> to startButton_Click. FOUR: Back in startButton_Click. Task getLengthTask is started. About to await getLengthTask -- no caller to return to. FIVE: Back in AccessTheWebAsync. Task getStringTask is complete. Processing the return statement. Exiting from AccessTheWebAsync. SIX: Back in startButton_Click. Task getLengthTask is finished. Result from AccessTheWebAsync is stored in contentLength. About to display contentLength and exit. Length of the downloaded string: 33946.
Analizzare il programma
Passaggi UNO e DUE
Le prime due righe di visualizzazione tracciano il percorso poiché startButton_Click
chiama AccessTheWebAsync
e AccessTheWebAsync
chiama il metodo asincrono HttpClient, ovvero GetStringAsync(String). Nell'immagine seguente vengono illustrate le chiamate metodo a metodo.
Il tipo restituito di AccessTheWebAsync
e client.GetStringAsync
è Task<TResult>. Per AccessTheWebAsync
TResult è un numero intero. Per GetStringAsync
TResult è una stringa. Per altre informazioni sui tipi restituiti dei metodi asincroni, vedere Tipi restituiti asincroni (Visual Basic).
Un metodo asincrono che restituisce un'attività restituisce un'istanza dell'attività quando il controllo torna al chiamante. Il controllo viene restituito da un metodo asincrono al relativo chiamante quando viene rilevato un operatore Await
nel metodo chiamato o quando termina il metodo chiamato. Le righe evidenziate con le etichette da "THREE" a "SIX" analizzano questa parte del processo.
Passaggio TRE
In AccessTheWebAsync
, il metodo asincrono GetStringAsync(String) viene chiamato per scaricare il contenuto della pagina Web di destinazione. Il controllo viene restituito da client.GetStringAsync
a AccessTheWebAsync
quando viene restituito client.GetStringAsync
.
Il metodo client.GetStringAsync
restituisce un'attività di stringa che viene assegnata alla variabile getStringTask
in AccessTheWebAsync
. La riga seguente nel programma di esempio indica la chiamata a client.GetStringAsync
e l'assegnazione.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
Si può pensare all'attività come a una promessa fatta da client.GetStringAsync
di produrre una stringa reale alla fine. Nel frattempo, se AccessTheWebAsync
ha del lavoro da svolgere che non dipende dalla stringa promessa da client.GetStringAsync
, il lavoro può continuare mentre client.GetStringAsync
rimane in attesa. Nell'esempio, le righe di output seguenti, che sono contrassegnate con "THREE", rappresentano la possibilità di eseguire operazioni indipendenti
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
L'istruzione seguente sospende lo stato di avanzamento in AccessTheWebAsync
quando si attende getStringTask
.
Dim urlContents As String = Await getStringTask
L'immagine che segue illustra il flusso di controllo da client.GetStringAsync
all'assegnazione a getStringTask
e dalla creazione di getStringTask
all'applicazione di un operatore Await.
L'espressione await sospende AccessTheWebAsync
finché non viene restituito client.GetStringAsync
. Nel frattempo il controllo viene restituito al chiamante di AccessTheWebAsync
, startButton_Click
.
Nota
In genere, la chiamata a un metodo asincrono si attende immediatamente. Ad esempio, l'assegnazione seguente potrebbe sostituire il codice precedente che crea e quindi attende getStringTask
:Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")
In questo argomento l'operatore await viene applicato in un secondo tempo per contenere le righe di output che indicano il flusso di controllo attraverso il programma.
Passaggio QUATTRO
Il tipo restituito dichiarato di AccessTheWebAsync
è Task(Of Integer)
. Di conseguenza, quando AccessTheWebAsync
è sospeso, restituisce un'attività di valori integer a startButton_Click
. È necessario comprendere che l'attività restituita non è getStringTask
. L'attività restituita è una nuova attività di valori integer che rappresenta ciò che resta da eseguire nel metodo sospeso, AccessTheWebAsync
. L'attività è una promessa da parte di AccessTheWebAsync
di produrre un numero intero al termine dell'attività.
L'istruzione seguente assegna questa attività alla variabile getLengthTask
.
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Come in AccessTheWebAsync
, startButton_Click
può continuare a eseguire operazioni che non dipendono dai risultati dell'attività asincrona (getLengthTask
) finché si è in attesa dell'attività. Le seguenti righe di output rappresentano tali operazioni:
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
Lo stato di avanzamento in startButton_Click
viene sospeso quando si attende getLengthTask
. La seguente istruzione di assegnazione sospende startButton_Click
finché non si completa AccessTheWebAsync
.
Dim contentLength As Integer = Await getLengthTask
Nella figura seguente le frecce indicano il flusso di controllo dall'espressione await in AccessTheWebAsync
all'assegnazione di un valore a getLengthTask
, seguita dall'elaborazione normale in startButton_Click
finché si è in attesa di getLengthTask
.
Passaggio CINQUE
Quando l'attività client.GetStringAsync
segnala il proprio completamento, l'elaborazione in AccessTheWebAsync
viene rilasciata dalla sospensione e può continuare oltre l'istruzione await. Le seguenti righe di output rappresentano la ripresa dell'elaborazione:
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
L'operando dell'istruzione return, urlContents.Length
, viene archiviato nell'attività restituita da AccessTheWebAsync
. L'espressione await recupera tale valore da getLengthTask
in startButton_Click
.
L'immagine seguente illustra il trasferimento del controllo dopo il completamento di client.GetStringAsync
(e getStringTask
).
AccessTheWebAsync
viene eseguita fino al completamento e il controllo viene restituito a startButton_Click
, che è in attesa del completamento.
Passaggio SEI
Quando l'attività AccessTheWebAsync
segnala il proprio completamento, l'elaborazione può continuare oltre l'istruzione await in startButton_Async
. Di fatto il programma non ha altre operazioni da eseguire.
Le seguenti righe di output rappresentano la ripresa dell'elaborazione in startButton_Async
:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
L'espressione await recupera da getLengthTask
il valore integer che rappresenta l'operando dell'istruzione return in AccessTheWebAsync
. L'istruzione seguente assegna tale valore alla variabile contentLength
.
Dim contentLength As Integer = Await getLengthTask
La figura seguente illustra la restituzione del controllo da AccessTheWebAsync
a startButton_Click
.
Vedi anche
- Programmazione asincrona con Async e Await (Visual Basic)
- Tipi restituiti asincroni (Visual Basic)
- Procedura dettagliata: Accesso al Web con Async e Await (Visual Basic)
- Async Sample: Control Flow in Async Programs (C# and Visual Basic) (Esempio di attività asincrona: Flusso di controllo in programmi asincroni (C# e Visual Basic))