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.
Rozbalte stažený soubor a spusťte Visual Studio.
Na řádku nabídek zvolte Soubor, Otevřít, Projekt nebo Řešení.
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:
Spusťte Visual Studio.
Na řádku nabídek zvolte Soubor, Nový, Projekt.
Otevře se dialogové okno Nový projekt .
V podokně Nainstalované šablony zvolte Visual Basic a pak v seznamu typů projektů zvolte Aplikaci WPF.
Zadejte
AsyncTracer
název projektu a pak zvolte tlačítko OK .Nový projekt se zobrazí v Průzkumník řešení.
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.
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.
Přidejte odkaz pro System.Net.Http.
V Průzkumník řešení otevřete místní nabídku pro MainWindow.xaml.vb a pak zvolte Zobrazit kód.
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
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í AccessTheWebAsync
a AccessTheWebAsync
volá asynchronní HttpClient metodu GetStringAsync(String). Následující obrázek popisuje volání z metody do metody.
Návratový typ obou AccessTheWebAsync
a client.GetStringAsync
je Task<TResult>. Hodnota AccessTheWebAsync
TResult 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 AccessTheWebAsync
getStringTask
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.
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 AccessTheWebAsync
pří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.
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.Length
je 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
) .
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_Async
souboru . 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
.