Sdílet prostřednictvím


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

Asynchronní programy můžete psát a udržovat snadněji pomocí klíčových slov Async a Await. 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 představena 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.

Nastavení 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 vám umožní otevřít a spustit 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.

Postavte si program sami

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íku ř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íku ř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íku řešení otevřete kontextovou nabídku pro MainWindow.xaml.vb a pak zvolte Zobrazit zdroj.

  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.
    

Sledování programu

Kroky 1 a DVA

První dva zobrazené řádky sledují cestu jako startButton_Click volá AccessTheWebAsync, a AccessTheWebAsync volá asynchronní metodu HttpClientGetStringAsync(String). Následující obrázek znázorňuje volání z metody do metody.

Kroky JEDNA a DVA

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 úlohy, když se kontrola vrátí zpět k volajícímu. Řízení se vrátí z asynchronní metody volajícímu buď když je operátor Await nalezen v volané metodě, nebo když volaná metoda skončí. Řádky displeje, které jsou označeny jako "TŘI" až "ŠEST", zaznamenávají tuto část procesu.

Krok 3

V AccessTheWebAsync se volá asynchronní metoda GetStringAsync(String), aby stáhla obsah cílové webové stránky. Ovládání se vrátí z client.GetStringAsync do AccessTheWebAsync když se client.GetStringAsync vrátí.

Metoda client.GetStringAsync vrátí úlohu řetězce, který je přiřazen k getStringTask proměnné v AccessTheWebAsync. V následujícím řádku ukázkového programu je ukázáno 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 vyprodukuje skutečný řetězec. Do té doby, pokud má AccessTheWebAsync práci, která nezávisí na slibovaném řetězci od client.GetStringAsync, tato práce může pokračovat, zatímco client.GetStringAsync čeká. 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 v AccessTheWebAsync během čekání na getStringTask.

Dim urlContents As String = Await getStringTask

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

Krok 3

Výraz await pozastaví AccessTheWebAsync, dokud se client.GetStringAsync nevrátí. Mezitím se řízení 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ý vytváří a poté č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 k zpracování výstupních řádků, které označují proces řízení v programu.

Krok 4

Deklarovaný návratový AccessTheWebAsync typ je Task(Of Integer). Proto když je AccessTheWebAsync pozastaveno, vrátí úkol s celočíselným výsledkem do startButton_Click. Měli byste pochopit, že vrácený úkol není getStringTask. Vrácený úkol je novým úkolem typu celé číslo, který reprezentuje zbývající práci v pozastavené metodě, AccessTheWebAsync. Úkol je příslibem od AccessTheWebAsync vytvořit 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 AccessTheWebAsync, startButton_Click může pokračovat v práci, která nezávisí na výsledcích asynchronní úlohy (getLengthTask), dokud se tato úloha nečeká. Následující výstupní řádky představují tuto práci:

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

Průběh startButton_Click se pozastaví, když se čeká na getLengthTask. Příkaz přiřazení pozastaví startButton_Click do doby, než bude AccessTheWebAsync 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.

Krok ČTYŘI

Krok PĚT

Když client.GetStringAsync signalizuje, že je dokončeno, zpracování AccessTheWebAsync se uvolní z pozastavení a může pokračovat za příkazem 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 tuto hodnotu z getLengthTask v rámci startButton_Click.

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

Krok pět

AccessTheWebAsync dokončí běh, a řízení se vrátí k startButton_Click, který čeká na dokončení.

Krok ŠEST

Když AccessTheWebAsync signalizuje, že je dokončeno, zpracování může pokračovat po příkazu await v startButton_Async. 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.

Krok ŠEST

Viz také