Controlestroom in Async-programma's (Visual Basic)
U kunt asynchrone programma's eenvoudiger schrijven en onderhouden met behulp van de Async
en Await
trefwoorden. De resultaten kunnen u echter verrassen als u niet begrijpt hoe uw programma werkt. Dit onderwerp traceert de controlestroom via een eenvoudig asynchroon programma om u te laten zien wanneer het besturingselement van de ene methode naar de andere wordt verplaatst en welke informatie telkens wordt overgedragen.
Notitie
De Async
trefwoorden en Await
trefwoorden zijn geïntroduceerd in Visual Studio 2012.
Over het algemeen markeert u methoden die asynchrone code bevatten met de Asynchrone wijziging. In een methode die is gemarkeerd met een asynchrone wijziging, kunt u een Operator Await (Visual Basic) gebruiken om op te geven waar de methode wordt onderbroken om te wachten tot een aangeroepen asynchroon proces is voltooid. Zie Asynchroon programmeren met Async en Await (Visual Basic) voor meer informatie.
In het volgende voorbeeld worden asynchrone methoden gebruikt om de inhoud van een opgegeven website als tekenreeks te downloaden en de lengte van de tekenreeks weer te geven. Het voorbeeld bevat de volgende twee methoden.
startButton_Click
, waarmee het resultaat wordt aanroepenAccessTheWebAsync
en weergegeven.AccessTheWebAsync
, waarmee de inhoud van een website als tekenreeks wordt gedownload en de lengte van de tekenreeks wordt geretourneerd.AccessTheWebAsync
gebruikt een asynchrone HttpClient methode GetStringAsync(String)om de inhoud te downloaden.
Genummerde weergavelijnen worden weergegeven op strategische punten in het programma om u te helpen begrijpen hoe het programma wordt uitgevoerd en om uit te leggen wat er gebeurt op elk punt dat is gemarkeerd. De weergavelijnen hebben het label 'ONE' tot en met 'SIX'. De labels vertegenwoordigen de volgorde waarin het programma deze coderegels bereikt.
De volgende code toont een overzicht van het 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
Elk van de gelabelde locaties, 'ONE' tot en met 'ZES', geeft informatie weer over de huidige status van het programma. De volgende uitvoer wordt geproduceerd:
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.
Het programma instellen
U kunt de code downloaden die in dit onderwerp wordt gebruikt vanuit MSDN, of u kunt deze zelf bouwen.
Notitie
Als u het voorbeeld wilt uitvoeren, moet Visual Studio 2012 of hoger en .NET Framework 4.5 of hoger op uw computer zijn geïnstalleerd.
Het programma downloaden
U kunt de toepassing voor dit onderwerp downloaden uit Async Sample: Control Flow in Async Programs. De volgende stappen worden geopend en uitgevoerd.
Pak het gedownloade bestand uit en start Visual Studio.
Kies Bestand, Openen, Project/Oplossing in de menubalk.
Navigeer naar de map met de uitgepakte voorbeeldcode, open het oplossingsbestand (.sln) en kies vervolgens de F5-sleutel om het project te bouwen en uit te voeren.
Zelf het programma bouwen
Het volgende WpF-project (Windows Presentation Foundation) bevat het codevoorbeeld voor dit onderwerp.
Voer de volgende stappen uit om het project uit te voeren:
Start Visual Studio.
Kies Bestand, Nieuw, Project in de menubalk.
Het dialoogvenster Nieuw project wordt geopend.
Kies Visual Basic in het deelvenster Geïnstalleerde sjablonen en kies vervolgens WPF-toepassing in de lijst met projecttypen.
Voer
AsyncTracer
de naam van het project in en kies vervolgens de knop OK .Het nieuwe project wordt weergegeven in Solution Explorer.
Kies in de Visual Studio Code-editor het tabblad MainWindow.xaml .
Als het tabblad niet zichtbaar is, opent u het snelmenu voor MainWindow.xaml in Solution Explorer en kiest u Code weergeven.
Vervang in de XAML-weergave van MainWindow.xaml de code door de volgende code.
<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>
Een eenvoudig venster met een tekstvak en een knop wordt weergegeven in de ontwerpweergave van MainWindow.xaml.
Voeg een verwijzing toe voor System.Net.Http.
Open in Solution Explorer het snelmenu voor MainWindow.xaml.vb en kies Code weergeven.
Vervang in MainWindow.xaml.vb de code door de volgende code.
' 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
Kies de F5-toets om het programma uit te voeren en kies vervolgens de knop Start .
De volgende uitvoer moet worden weergegeven:
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.
Het programma traceren
Stap ÉÉN en TWEE
De eerste twee weergavelijnen traceren het pad als startButton_Click
aanroepen AccessTheWebAsync
en AccessTheWebAsync
roepen de asynchrone HttpClient methode GetStringAsync(String)aan. In de volgende afbeelding ziet u een overzicht van de aanroepen van de methode naar de methode.
Het retourtype van beide AccessTheWebAsync
en client.GetStringAsync
is Task<TResult>. Voor AccessTheWebAsync
TResult is een geheel getal. TResult GetStringAsync
is een tekenreeks. Zie Asynchrone retourtypen (Visual Basic) voor meer informatie over retourtypen van asynchrone methoden.
Een asynchrone methode die een taak retourneert, retourneert een taakexemplaren wanneer het besturingselement wordt teruggezet naar de aanroeper. Het besturingselement retourneert van een asynchrone methode naar de aanroeper wanneer een Await
operator wordt aangetroffen in de aangeroepen methode of wanneer de aangeroepen methode eindigt. De weergavelijnen met het label 'DRIE' tot en met 'SIX' traceren dit deel van het proces.
Stap DRIE
In AccessTheWebAsync
wordt de asynchrone methode GetStringAsync(String) aangeroepen om de inhoud van de doelwebpagina te downloaden. Het besturingselement keert terug van client.GetStringAsync
naar AccessTheWebAsync
wanneer client.GetStringAsync
het retourneert.
De client.GetStringAsync
methode retourneert een taak van een tekenreeks die is toegewezen aan de getStringTask
variabele in AccessTheWebAsync
. In de volgende regel in het voorbeeldprogramma ziet u de aanroep van client.GetStringAsync
en de toewijzing.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
U kunt de taak zien als een belofte door client.GetStringAsync
uiteindelijk een werkelijke tekenreeks te produceren. In de tussentijd, als AccessTheWebAsync
er werk moet worden uitgevoerd dat niet afhankelijk is van de beloofde tekenreeks van client.GetStringAsync
, kan dat werk worden voortgezet terwijl client.GetStringAsync
er wordt gewacht. In het voorbeeld vertegenwoordigen de volgende uitvoerregels, die het label 'DRIE' hebben, de mogelijkheid om onafhankelijk werk uit te voeren
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
De volgende instructie onderbreekt de voortgang AccessTheWebAsync
wanneer getStringTask
wordt gewacht.
Dim urlContents As String = Await getStringTask
In de volgende afbeelding ziet u de controlestroom van client.GetStringAsync
naar de toewijzing van getStringTask
en van het maken van getStringTask
de toepassing van een Await-operator.
De wachtexpressie wordt opgeschort AccessTheWebAsync
totdat client.GetStringAsync
de expressie wordt geretourneerd. Ondertussen keert het besturingselement terug naar de beller van AccessTheWebAsync
, startButton_Click
.
Notitie
Normaal gesproken wacht u onmiddellijk op de aanroep van een asynchrone methode. De volgende toewijzing kan bijvoorbeeld de vorige code vervangen die wordt gemaakt en wacht vervolgens op getStringTask
: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")
In dit onderwerp wordt de wachtoperator later toegepast om plaats te bieden aan de uitvoerregels die de controlestroom via het programma markeren.
Stap VIER
Het gedeclareerde retourtype AccessTheWebAsync
is Task(Of Integer)
. Daarom, wanneer AccessTheWebAsync
wordt onderbroken, retourneert het een taak van geheel getal naar startButton_Click
. U moet begrijpen dat de geretourneerde taak niet getStringTask
is. De geretourneerde taak is een nieuwe taak van een geheel getal dat aangeeft wat er nog moet worden gedaan in de onderbroken methode, AccessTheWebAsync
. De taak is een belofte van het produceren van AccessTheWebAsync
een geheel getal wanneer de taak is voltooid.
Met de volgende instructie wordt deze taak toegewezen aan de getLengthTask
variabele.
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Zoals in AccessTheWebAsync
, startButton_Click
kan doorgaan met werk dat niet afhankelijk is van de resultaten van de asynchrone taak (getLengthTask
) totdat de taak wordt verwacht. De volgende uitvoerlijnen vertegenwoordigen dat werk:
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
startButton_Click
De voortgang wordt opgeschort wanneer getLengthTask
wordt gewacht. De volgende toewijzingsinstructie startButton_Click
wordt opgeschort totdat AccessTheWebAsync
deze is voltooid.
Dim contentLength As Integer = Await getLengthTask
In de volgende afbeelding tonen de pijlen de controlestroom van de wachtexpressie in AccessTheWebAsync
de toewijzing van een waarde aan getLengthTask
, gevolgd door de normale verwerking totdat startButton_Click
getLengthTask
wordt gewacht.
Stap VIJF
Wanneer client.GetStringAsync
de signalen zijn voltooid, wordt de verwerking AccessTheWebAsync
vrijgegeven na de schorsing en kan deze verdergaan dan de await-instructie. De volgende uitvoerregels vertegenwoordigen de hervatting van de verwerking:
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
De operand van de retourinstructie, urlContents.Length
wordt opgeslagen in de taak die AccessTheWebAsync
wordt geretourneerd. De await-expressie haalt die waarde op uit getLengthTask
in startButton_Click
.
In de volgende afbeelding ziet u de overdracht van het besturingselement nadat client.GetStringAsync
(en getStringTask
) is voltooid.
AccessTheWebAsync
wordt uitgevoerd tot voltooiing en het besturingselement keert terug naar startButton_Click
, dat wacht op de voltooiing.
Stap ZES
Wanneer AccessTheWebAsync
er signalen zijn dat het is voltooid, kan de verwerking verdergaan dan de await-instructie in startButton_Async
. In feite heeft het programma niets meer te doen.
De volgende uitvoerregels vertegenwoordigen de hervatting van de verwerking 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.
De await-expressie wordt opgehaald uit getLengthTask
de gehele waarde die de operand is van de retourinstructie in AccessTheWebAsync
. Met de volgende instructie wordt die waarde toegewezen aan de contentLength
variabele.
Dim contentLength As Integer = Await getLengthTask
In de volgende afbeelding ziet u de terugkeer van het besturingselement van AccessTheWebAsync
naar startButton_Click
.