Kontrollflöde i Async-program (Visual Basic)

Du kan skriva och underhålla asynkrona program enklare med hjälp av nyckelorden Async och Await . Resultatet kan dock överraska dig om du inte förstår hur programmet fungerar. Det här avsnittet spårar kontrollflödet via ett enkelt asynkront program för att visa dig när kontrollen flyttas från en metod till en annan och vilken information som överförs varje gång.

Kommentar

Nyckelorden Async och Await introducerades i Visual Studio 2012.

I allmänhet markerar du metoder som innehåller asynkron kod med Async-modifieraren . I en metod som är markerad med en asynkron modifierare kan du använda operatorn Await (Visual Basic) för att ange var metoden pausar för att vänta tills en så kallad asynkron process har slutförts. Mer information finns i Asynkron programmering med Async och Await (Visual Basic).

I följande exempel används asynkrona metoder för att ladda ned innehållet på en angiven webbplats som en sträng och för att visa längden på strängen. Exemplet innehåller följande två metoder.

  • startButton_Click, som anropar AccessTheWebAsync och visar resultatet.

  • AccessTheWebAsync, som laddar ned innehållet på en webbplats som en sträng och returnerar längden på strängen. AccessTheWebAsync använder en asynkron HttpClient metod, GetStringAsync(String), för att ladda ned innehållet.

Numrerade visningslinjer visas på strategiska punkter i hela programmet för att hjälpa dig att förstå hur programmet körs och för att förklara vad som händer vid varje punkt som markeras. Visningsraderna är märkta "ONE" till "SIX". Etiketterna representerar i vilken ordning programmet når dessa kodrader.

Följande kod visar en disposition av programmet.

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

Var och en av de märkta platserna, "ONE" till "SIX", visar information om programmets aktuella tillstånd. Följande utdata genereras:

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.

Konfigurera programmet

Du kan ladda ned koden som det här avsnittet använder från MSDN, eller så kan du skapa den själv.

Kommentar

Om du vill köra exemplet måste du ha Visual Studio 2012 eller senare och .NET Framework 4.5 eller senare installerat på datorn.

Ladda ned programmet

Du kan ladda ned programmet för det här ämnet från Async Sample: Control Flow i Async-program. Följande steg öppnar och kör programmet.

  1. Packa upp den nedladdade filen och starta sedan Visual Studio.

  2. På menyraden väljer du Arkiv, Öppna, Projekt/Lösning.

  3. Gå till mappen som innehåller den uppackade exempelkoden, öppna lösningen (.sln) och välj sedan F5-nyckeln för att skapa och köra projektet.

Skapa programmet själv

Följande WPF-projekt (Windows Presentation Foundation) innehåller kodexemplet för det här ämnet.

Utför följande steg för att köra projektet:

  1. Starta Visual Studio.

  2. På menyraden väljer du Arkiv, Nytt, Projekt.

    Dialogrutan Nytt projekt öppnas.

  3. I fönstret Installerade mallar väljer du Visual Basic och sedan WPF-program i listan över projekttyper.

  4. Ange AsyncTracer som namnet på projektet och välj sedan ok-knappen .

    Det nya projektet visas i Solution Explorer.

  5. I Visual Studio Code-redigeraren väljer du fliken MainWindow.xaml .

    Om fliken inte visas öppnar du snabbmenyn för MainWindow.xaml i Solution Explorer och väljer sedan Visa kod.

  6. I XAML-vyn i MainWindow.xaml ersätter du koden med följande kod.

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

    Ett enkelt fönster som innehåller en textruta och en knapp visas i designvyn för MainWindow.xaml.

  7. Lägg till en referens för System.Net.Http.

  8. Öppna snabbmenyn för MainWindow.xaml.vb i Solution Explorer och välj sedan Visa kod.

  9. I MainWindow.xaml.vb ersätter du koden med följande kod.

    ' 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. Välj F5-tangenten för att köra programmet och välj sedan knappen Start .

    Följande utdata bör visas:

    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.
    

Spåra programmet

Steg ETT och TVÅ

De första två visningsraderna spårar sökvägen som startButton_Click anrop AccessTheWebAsyncoch AccessTheWebAsync anropar den asynkrona HttpClient metoden GetStringAsync(String). Följande bild beskriver anropen från metod till metod.

Steps ONE and TWO

Returtypen för båda AccessTheWebAsync och client.GetStringAsync är Task<TResult>. För AccessTheWebAsyncär TResult ett heltal. För GetStringAsyncär TResult en sträng. Mer information om returtyper för asynkron metod finns i Async Return Types (Visual Basic).

En aktivitetsreturerande asynkron metod returnerar en aktivitetsinstans när kontrollen flyttas tillbaka till anroparen. Kontrollen returnerar från en asynkron metod till anroparen antingen när en Await operator påträffas i den anropade metoden eller när den anropade metoden slutar. De visningsrader som är märkta "THREE" till "SIX" spårar den här delen av processen.

Steg TRE

I AccessTheWebAsyncanropas den asynkrona metoden GetStringAsync(String) för att ladda ned innehållet på målwebbsidan. Kontrollen returnerar från client.GetStringAsync till AccessTheWebAsync när client.GetStringAsync returneras.

Metoden client.GetStringAsync returnerar en uppgift med strängen som har tilldelats variabeln getStringTask i AccessTheWebAsync. Följande rad i exempelprogrammet visar anropet till client.GetStringAsync och tilldelningen.

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

Du kan se uppgiften som ett löfte genom client.GetStringAsync att skapa en verklig sträng så småningom. Under tiden, om AccessTheWebAsync har arbete att göra som inte beror på den utlovade strängen från client.GetStringAsync, kan det arbetet fortsätta medan client.GetStringAsync väntar. I exemplet representerar följande rader med utdata, som är märkta "THREE", möjligheten att utföra oberoende arbete

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

Följande instruktion pausar förloppet i AccessTheWebAsync när getStringTask inväntas.

Dim urlContents As String = Await getStringTask

Följande bild visar flödet av kontroll från client.GetStringAsync till tilldelningen till getStringTask och från skapandet av getStringTask till programmet för en Await-operator.

Step THREE

Await-uttrycket pausas tills client.GetStringAsync det returnerasAccessTheWebAsync. Under tiden återgår kontrollen till anroparen för AccessTheWebAsync, startButton_Click.

Kommentar

Vanligtvis väntar du på anropet till en asynkron metod omedelbart. Följande tilldelning kan till exempel ersätta den tidigare koden som skapar och sedan väntar getStringTaskpå : Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")

I det här avsnittet tillämpas inväntningsoperatorn senare för att hantera de utdatarader som markerar kontrollflödet genom programmet.

Steg FYRA

Den deklarerade returtypen AccessTheWebAsync är Task(Of Integer). AccessTheWebAsync När pausas returneras därför en aktivitet med heltal till startButton_Click. Du bör förstå att den returnerade uppgiften inte getStringTaskär . Den returnerade aktiviteten är en ny uppgift med heltal som representerar vad som återstår att göra i den inaktiverade metoden . AccessTheWebAsync Uppgiften är ett löfte från AccessTheWebAsync för att skapa ett heltal när aktiviteten är klar.

Följande instruktion tilldelar den här aktiviteten till variabeln getLengthTask .

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

Som i AccessTheWebAsynckan startButton_Click fortsätta med arbete som inte är beroende av resultatet av den asynkrona aktiviteten (getLengthTask) tills aktiviteten väntar. Följande utdatarader representerar det arbetet:

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

Förloppet i startButton_Click pausas när getLengthTask inväntas. Följande tilldelningsinstruktor pausas startButton_Click tills AccessTheWebAsync den är klar.

Dim contentLength As Integer = Await getLengthTask

I följande bild visar pilarna kontrollflödet från inväntningsuttrycket i AccessTheWebAsync till tilldelningen av ett värde till getLengthTask, följt av normal bearbetning i startButton_Click tills getLengthTask väntar.

Step FOUR

Steg FEM

När client.GetStringAsync signaler om att den är klar frisläpps bearbetningen från AccessTheWebAsync avstängning och kan fortsätta förbi await-instruktionen. Följande rader med utdata representerar återupptagandet av bearbetningen:

FIVE:  Back in AccessTheWebAsync.
           Task getStringTask is complete.
           Processing the return statement.
           Exiting from AccessTheWebAsync.

Operand för retursatsen, urlContents.Length, lagras i den uppgift som AccessTheWebAsync returneras. Await-uttrycket hämtar det värdet från getLengthTask i startButton_Click.

Följande bild visar överföringen av kontrollen efter client.GetStringAsync att (och getStringTask) har slutförts.

Step FIVE

AccessTheWebAsync körs till slutförande och kontrollen återgår till startButton_Click, som väntar på att slutföras.

Steg SEX

När AccessTheWebAsync signaler om att den är klar kan bearbetningen fortsätta förbi await-instruktionen i startButton_Async. Faktum är att programmet inte har något mer att göra.

Följande rader med utdata representerar återupptagandet av bearbetningen i startButton_Async:

SIX:   Back in startButton_Click.
           Task getLengthTask is finished.
           Result from AccessTheWebAsync is stored in contentLength.
           About to display contentLength and exit.

Await-uttrycket hämtas från getLengthTask heltalsvärdet som är operand för retursatsen i AccessTheWebAsync. Följande instruktion tilldelar det värdet till variabeln contentLength .

Dim contentLength As Integer = Await getLengthTask

Följande bild visar returen av kontrollen från AccessTheWebAsync till startButton_Click.

Step SIX

Se även