Condividi tramite


Flusso di controllo nei programmi asincroni (Visual Basic)

È possibile scrivere e gestire programmi asincroni più facilmente usando le Async parole chiave e Await . Tuttavia, i risultati potrebbero sorprendere se non si capisce come funziona il programma. Questo argomento analizza il flusso del controllo tramite un semplice programma asincrono per mostrare quando il controllo passa da un metodo a un altro e quali informazioni vengono trasferite ogni volta.

Annotazioni

Le Async parole chiave 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 asincrono, è possibile usare un operatore Await (Visual Basic) per specificare dove il metodo viene sospeso per attendere il completamento di un processo asincrono chiamato. Per altre informazioni, vedere Programmazione asincrona con Async e Await (Visual Basic).

Nell'esempio seguente vengono utilizzati metodi asincroni per scaricare il contenuto di un sito Web specificato come stringa e per visualizzare la lunghezza della stringa. L'esempio contiene i due metodi seguenti.

  • startButton_Click, che chiama AccessTheWebAsync 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 asincrono HttpClient , GetStringAsync(String), per scaricare il contenuto.

Le linee di visualizzazione numerate vengono visualizzate in punti strategici in tutto il programma per comprendere come viene eseguito il programma e spiegare cosa accade in ogni punto contrassegnato. Le linee di visualizzazione sono etichettate da "ONE" a "SIX". Le etichette rappresentano l'ordine in cui il programma raggiunge queste righe di codice.

Il codice seguente illustra 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 etichettate, da "ONE" a "SIX", visualizza informazioni sullo stato corrente del programma. Viene generato 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.

Configurare il programma

È possibile scaricare il codice usato da questo argomento da MSDN oppure compilarlo manualmente.

Annotazioni

Per eseguire l'esempio, è necessario che Nel computer sia installato Visual Studio 2012 o versione successiva e .NET Framework 4.5 o versione successiva.

Scaricare il programma

È possibile scaricare l'applicazione per questo argomento da Async Sample: Control Flow in Async Programs (Esempio asincrono: Flusso di controllo nei programmi asincroni). I passaggi seguenti aprono ed eseguono il programma.

  1. Decomprimere il file scaricato e quindi avviare Visual Studio.

  2. Sulla barra dei menu scegliere File, Apri, Progetto/Soluzione.

  3. Passare alla cartella che contiene il codice di esempio decompresso, aprire il file della soluzione (.sln) e quindi scegliere la chiave F5 per compilare ed eseguire il progetto.

Creare il programma manualmente

Il progetto Windows Presentation Foundation (WPF) seguente contiene l'esempio di codice per questo argomento.

Per eseguire il progetto, seguire questa procedura:

  1. Avvia Visual Studio.

  2. Nella barra dei menu scegliere File, Nuovo, Progetto.

    Verrà visualizzata la finestra di dialogo Nuovo progetto .

  3. Nel riquadro Modelli installati scegliere Visual Basic e quindi scegliere Applicazione WPF dall'elenco dei tipi di progetto.

  4. Immettere AsyncTracer come nome del progetto e quindi scegliere il pulsante OK .

    Il nuovo progetto verrà visualizzato in Esplora soluzioni.

  5. 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 quindi scegliere Visualizza codice.

  6. Nella visualizzazione XAML di MainWindow.xaml sostituire il codice con il codice seguente.

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

    Una finestra semplice che contiene una casella di testo e un pulsante viene visualizzato nella visualizzazione Progettazione di MainWindow.xaml.

  7. Aggiungere un riferimento per System.Net.Http.

  8. In Esplora soluzioni aprire il menu di scelta rapida per MainWindow.xaml.vb e quindi scegliere Visualizza codice.

  9. In MainWindow.xaml.vb sostituire il codice con il codice seguente.

    ' 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
    
  10. Scegliere il tasto F5 per eseguire il programma e quindi scegliere il pulsante Start .

    Verrà 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.
    

Traccia il programma

Passaggi uno e due

Le prime due righe di visualizzazione tracciano il percorso come startButton_Click chiama AccessTheWebAsynce AccessTheWebAsync chiama il metodo HttpClientasincrono GetStringAsync(String) . L'immagine seguente illustra le chiamate tra i metodi.

Passaggi UNO e DUE

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 dal metodo asincrono, vedere Tipi restituiti asincroni (Visual Basic).For more information about async method return types, see Async Return Types (Visual Basic).

Un metodo asincrono che restituisce un'attività restituisce un'istanza dell'attività quando il controllo torna al chiamante. Il controllo ritorna da un metodo asincrono al chiamante quando si incontra un operatore Await nel metodo chiamato o quando il metodo chiamato termina. Le righe di visualizzazione etichettate da "THREE" a "SIX" documentano questa parte del processo.

Passaggio TRE

In AccessTheWebAsyncviene chiamato il metodo GetStringAsync(String) asincrono per scaricare il contenuto della pagina Web di destinazione. Il controllo restituisce da client.GetStringAsync a AccessTheWebAsync quando client.GetStringAsync viene restituito.

Il client.GetStringAsync metodo restituisce un'attività di stringa assegnata alla getStringTask variabile in AccessTheWebAsync. La riga seguente nel programma di esempio mostra la chiamata a client.GetStringAsync e l'assegnazione.

Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")

È possibile considerare l'attività come una promessa di client.GetStringAsync di produrre una stringa effettiva in futuro. Nel frattempo, se AccessTheWebAsync ha del lavoro che non dipende dalla stringa promessa da client.GetStringAsync, quel lavoro può continuare mentre client.GetStringAsync aspetta. Nell'esempio, le righe di output seguenti, etichettate come "THREE", rappresentano l'opportunità di eseguire operazioni indipendenti

THREE: Back in AccessTheWebAsync.
           Task getStringTask is started.
           About to await getStringTask & return a Task<int> to startButton_Click.

La dichiarazione seguente sospende lo stato di avanzamento in AccessTheWebAsync quando getStringTask è atteso.

Dim urlContents As String = Await getStringTask

L'immagine seguente mostra il flusso di controllo da client.GetStringAsync all'assegnazione a getStringTask e dalla creazione di getStringTask all'applicazione di un operatore Await.

Passaggio TRE

L'espressione await si sospende AccessTheWebAsync finché client.GetStringAsync non restituisce. Nel frattempo, il controllo torna al chiamante di AccessTheWebAsync, startButton_Click.

Annotazioni

In genere, si attende immediatamente la chiamata a un metodo asincrono. 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 momento per contenere le righe di output che contrassegnano il flusso del controllo attraverso il programma.

Passaggio QUATTRO

Il tipo restituito dichiarato di AccessTheWebAsync è Task(Of Integer). Pertanto, quando AccessTheWebAsync viene sospeso, restituisce un'attività di integer a startButton_Click. È necessario comprendere che l'attività restituita non è getStringTask. L'attività restituita è una nuova attività di integer che rappresenta ciò che rimane da eseguire nel metodo sospeso, AccessTheWebAsync. L'attività è una promessa da AccessTheWebAsync di produrre un numero intero al suo completamento.

L'istruzione seguente assegna questa attività alla getLengthTask variabile .

Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()

Come in AccessTheWebAsync, startButton_Click può continuare con il lavoro che non dipende dai risultati dell'attività asincrona (getLengthTask) fino a quando l'attività non è attesa. Le righe di output seguenti rappresentano il lavoro.

FOUR:  Back in startButton_Click.
           Task getLengthTask is started.
           About to await getLengthTask -- no caller to return to.

L'avanzamento in startButton_Click è sospeso attendendo getLengthTask. L'istruzione di assegnazione seguente sospende startButton_Click fino al completamento di AccessTheWebAsync.

Dim contentLength As Integer = Await getLengthTask

Nell'illustrazione seguente, le frecce mostrano il flusso di controllo dall'espressione await in AccessTheWebAsync all'assegnazione di un valore a getLengthTask, seguito dall'elaborazione normale in startButton_Click fino a quando getLengthTask non viene atteso.

Passaggio QUATTRO

Passaggio CINQUE

Quando client.GetStringAsync segnala che è completa, l'elaborazione in AccessTheWebAsync viene rilasciata dalla sospensione e può continuare oltre l'istruzione await. Le righe di output seguenti 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à che AccessTheWebAsync restituisce. L'espressione await recupera tale valore da getLengthTask in startButton_Click.

L'immagine seguente mostra il trasferimento del controllo dopo il completamento di client.GetStringAsync (e getStringTask).

Passaggio CINQUE

AccessTheWebAsync viene eseguito fino al completamento, e il controllo ritorna a startButton_Click, che è in attesa del completamento.

Passaggio SEI

Quando AccessTheWebAsync segnala che è stata completata, l'elaborazione può continuare oltre l'istruzione await in startButton_Async. Infatti, il programma non ha più nulla da fare.

Le righe di output seguenti 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 dal getLengthTask valore intero che è l'operando dell'istruzione return in AccessTheWebAsync. L'istruzione seguente assegna tale valore alla contentLength variabile .

Dim contentLength As Integer = Await getLengthTask

L'immagine seguente mostra il ritorno del controllo da AccessTheWebAsync a startButton_Click.

Passaggio SEI

Vedere anche