Tok řízení v asynchronních programech (Visual Basic)

Asynchronní programy můžete psát a udržovat snadněji pomocí Async klíčových slov a Await používat je. Výsledky vás ale mohou překvapit, pokud nerozumíte tomu, jak váš program funguje. Toto téma sleduje tok řízení prostřednictvím jednoduchého asynchronního programu, který vám ukáže, kdy se ovládací prvek přesune z jedné metody do druhé a jaké informace se pokaždé přenesou.

Poznámka:

Klíčová slova Async a Await byla zavedena v sadě Visual Studio 2012.

Obecně lze označit metody, které obsahují asynchronní kód s modifikátorem Async . V metodě, která je označena asynchronním modifikátorem, můžete pomocí operátoru Await (Visual Basic) určit, kde metoda pozastaví čekání na dokončení volaný asynchronní proces. Další informace naleznete v tématu Asynchronní programování pomocí Async a Await (Visual Basic).

Následující příklad používá asynchronní metody ke stažení obsahu zadaného webu jako řetězec a k zobrazení délky řetězce. Příklad obsahuje následující dvě metody.

  • startButton_Click, která volá AccessTheWebAsync a zobrazuje výsledek.

  • AccessTheWebAsync, který stáhne obsah webu jako řetězec a vrátí délku řetězce. AccessTheWebAsync používá asynchronní HttpClient metodu , GetStringAsync(String)ke stažení obsahu.

Číslované zobrazované čáry se zobrazují v strategických bodech programu, které vám pomůžou pochopit, jak se program spouští, a vysvětlit, co se stane v jednotlivých označených bodech. Zobrazené řádky jsou označené jako "ONE" až "SIX". Popisky představují pořadí, ve kterém program dosáhne těchto řádků kódu.

Následující kód ukazuje osnovu programu.

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

Každá z označených umístění, "ONE" až "SIX", zobrazí informace o aktuálním stavu programu. Vytvoří se následující výstup:

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.

Vytvoření programu

Kód, který toto téma používá, si můžete stáhnout z MSDN nebo si ho můžete sestavit sami.

Poznámka:

Pokud chcete spustit příklad, musíte mít na počítači nainstalovanou sadu Visual Studio 2012 nebo novější a rozhraní .NET Framework 4.5 nebo novější.

Stažení programu

Aplikaci pro toto téma si můžete stáhnout z ukázky Async: Tok řízení v asynchronních programech. Následující kroky otevřete a spusťte program.

  1. Rozbalte stažený soubor a spusťte Visual Studio.

  2. Na řádku nabídek zvolte Soubor, Otevřít, Projekt nebo Řešení.

  3. Přejděte do složky, která obsahuje rozbalený ukázkový kód, otevřete soubor řešení (.sln) a zvolte klíč F5 pro sestavení a spuštění projektu.

Vytvoření programu vlastními silami

Následující projekt WPF (Windows Presentation Foundation) obsahuje příklad kódu pro toto téma.

Pokud chcete projekt spustit, proveďte následující kroky:

  1. Spusťte Visual Studio.

  2. Na řádku nabídek zvolte Soubor, Nový, Projekt.

    Otevře se dialogové okno Nový projekt .

  3. V podokně Nainstalované šablony zvolte Visual Basic a pak v seznamu typů projektů zvolte Aplikaci WPF.

  4. Zadejte AsyncTracer název projektu a pak zvolte tlačítko OK .

    Nový projekt se zobrazí v Průzkumník řešení.

  5. V editoru Visual Studio Code zvolte kartu MainWindow.xaml .

    Pokud karta není viditelná, otevřete místní nabídku pro MainWindow.xaml v Průzkumník řešení a pak zvolte Zobrazit kód.

  6. V zobrazení XAML MainWindow.xaml nahraďte kód následujícím kódem.

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

    Jednoduché okno, které obsahuje textové pole a tlačítko se zobrazí v návrhovém zobrazení MainWindow.xaml.

  7. Přidejte odkaz pro System.Net.Http.

  8. V Průzkumník řešení otevřete místní nabídku pro MainWindow.xaml.vb a pak zvolte Zobrazit kód.

  9. V MainWindow.xaml.vb nahraďte kód následujícím kódem.

    ' 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. Zvolte klávesu F5, aby se program spustil, a pak zvolte tlačítko Start .

    Měl by se zobrazit následující výstup:

    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.
    

Trasování programu

Kroky 1 a 2

První dva zobrazené řádky trasovat cestu jako startButton_Click volání AccessTheWebAsynca AccessTheWebAsync volá asynchronní HttpClient metodu GetStringAsync(String). Následující obrázek popisuje volání z metody do metody.

Steps ONE and TWO

Návratový typ obou AccessTheWebAsync a client.GetStringAsync je Task<TResult>. Hodnota AccessTheWebAsyncTResult je celé číslo. Pro GetStringAsync, TResult je řetězec. Další informace o asynchronních návratových typech metod naleznete v tématu Asynchronní návratové typy (Visual Basic).

Asynchronní metoda vracející úlohu vrátí instanci úkolu, když se řízení přesune zpět na volajícího. Ovládací prvek se vrátí z asynchronní metody volajícímu buď, když Await je operátor v volané metodě nebo když volána metoda končí. Zobrazené řádky, které jsou označeny jako "TŘI" až "SIX", trasují tuto část procesu.

Krok 3

V AccessTheWebAsync, asynchronní metoda GetStringAsync(String) je volána ke stažení obsahu cílové webové stránky. Ovládací prvek se vrátí z client.GetStringAsync hodnoty do AccessTheWebAsync návratu client.GetStringAsync .

Metoda client.GetStringAsync vrátí úlohu řetězce, který je přiřazen k getStringTask proměnné v AccessTheWebAsync. Následující řádek v ukázkovém programu ukazuje volání client.GetStringAsync a přiřazení.

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

Úkol si můžete představit jako příslib, který client.GetStringAsync nakonec vytvoří skutečný řetězec. Do té doby, pokud AccessTheWebAsync má práce na tom, že to nezávisí na slibovaném řetězci z client.GetStringAsync, tato práce může pokračovat, zatímco client.GetStringAsync čekání. V příkladu následující řádky výstupu, které jsou označeny jako TŘI, představují příležitost provádět nezávislou práci.

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

Následující příkaz pozastaví průběh AccessTheWebAsyncgetStringTask v očekávaném stavu.

Dim urlContents As String = Await getStringTask

Následující obrázek znázorňuje tok řízení z client.GetStringAsync přiřazení do getStringTask operátoru Await a z jeho vytvoření getStringTask do aplikace operátoru Await.

Step THREE

Výraz await se pozastaví AccessTheWebAsync , dokud client.GetStringAsync se nevrátí. Do té doby se ovládací prvek vrátí volajícímu AccessTheWebAsync. startButton_Click

Poznámka:

Obvykle očekáváte volání asynchronní metody okamžitě. Například následující přiřazení by mohlo nahradit předchozí kód, který vytvoří a pak čeká getStringTask: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")

V tomto tématu se operátor await použije později pro přizpůsobení výstupních řádků, které označují tok řízení prostřednictvím programu.

Krok 4

Deklarovaný návratový AccessTheWebAsync typ je Task(Of Integer). Proto při AccessTheWebAsync pozastavení vrátí úkol celé číslo do startButton_Click. Měli byste pochopit, že vrácený úkol není getStringTask. Vrácený úkol je nový úkol celého čísla, který představuje to, co je třeba provést v pozastavené metodě, AccessTheWebAsync. Úkol je příslibem, ze AccessTheWebAsync které se vytvoří celé číslo, když je úkol dokončen.

Následující příkaz přiřadí tento úkol proměnné getLengthTask .

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

Stejně jako v AccessTheWebAsyncpřípadě , startButton_Click může pokračovat v práci, která nezávisí na výsledcích asynchronní úlohy (getLengthTask), dokud se úkol nečeká. Následující výstupní řádky představují, že fungují:

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

startButton_Click Průběh se pozastaví, když getLengthTask se čeká. Následující příkaz přiřazení se pozastaví startButton_Click , dokud AccessTheWebAsync nebude dokončen.

Dim contentLength As Integer = Await getLengthTask

Na následujícím obrázku znázorňují šipky tok řízení z výrazu AccessTheWebAsync await do přiřazení hodnoty k getLengthTask, následované normálním zpracováním startButton_Click , dokud getLengthTask nebude očekáváno.

Step FOUR

Krok 5

Když client.GetStringAsync signály, že je dokončeno, zpracování AccessTheWebAsync se uvolní z pozastavení a může pokračovat po příkazu await. Následující řádky výstupu představují obnovení zpracování:

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

Operand návratového příkazu , urlContents.Lengthje uložen v úkolu, který AccessTheWebAsync vrací. Výraz await načte hodnotu z getLengthTask parametru in startButton_Click.

Následující obrázek znázorňuje přenos ovládacího prvku po client.GetStringAsync dokončení (a getStringTask) .

Step FIVE

AccessTheWebAsync se spustí na dokončení a ovládací prvek se vrátí do startButton_Click, který čeká na dokončení.

Krok 6

Když AccessTheWebAsync signály, že je dokončeno, zpracování může pokračovat po příkazu await v startButton_Asyncsouboru . Ve skutečnosti, program nemá nic víc dělat.

Následující řádky výstupu představují obnovení zpracování v startButton_Async:

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

Výraz await načte z getLengthTask celočíselné hodnoty, která je operandem příkazu return v AccessTheWebAsync. Následující příkaz přiřadí této hodnotě contentLength proměnné.

Dim contentLength As Integer = Await getLengthTask

Následující obrázek ukazuje návrat ovládacího prvku z AccessTheWebAsync do startButton_Click.

Step SIX

Viz také