Przepływ sterowania w programach asynchronicznych (Visual Basic)
Możesz łatwiej pisać i obsługiwać programy asynchroniczne przy użyciu Async
słów kluczowych i Await
. Jednak wyniki mogą cię zaskoczyć, jeśli nie rozumiesz sposobu działania programu. W tym temacie śledzenia przepływu sterowania za pomocą prostego programu asynchronicznego, aby pokazać, kiedy kontrolka przechodzi z jednej metody do innej i jakie informacje są przesyłane za każdym razem.
Uwaga
Słowa Async
kluczowe i Await
zostały wprowadzone w programie Visual Studio 2012.
Ogólnie rzecz biorąc, metody zawierające kod asynchroniczny są oznaczane modyfikatorem asynchronicznym . W metodzie oznaczonej modyfikatorem asynchronicznym można użyć operatora Await (Visual Basic), aby określić, gdzie metoda wstrzymuje się czekać na ukończenie wywoływanego procesu asynchronicznego. Aby uzyskać więcej informacji, zobacz Asynchroniczne programowanie za pomocą Async i Await (Visual Basic).
W poniższym przykładzie użyto metod asynchronicznych, aby pobrać zawartość określonej witryny internetowej jako ciąg i wyświetlić długość ciągu. Przykład zawiera następujące dwie metody.
startButton_Click
, który wywołujeAccessTheWebAsync
i wyświetla wynik.AccessTheWebAsync
, który pobiera zawartość witryny internetowej jako ciąg i zwraca długość ciągu.AccessTheWebAsync
Metoda asynchroniczna HttpClient używa metody GetStringAsync(String), aby pobrać zawartość.
Ponumerowane linie wyświetlania są wyświetlane w punktach strategicznych w całym programie, aby ułatwić zrozumienie sposobu działania programu i wyjaśnienie, co się dzieje w każdym punkcie oznaczonym. Wiersze wyświetlania są oznaczone etykietą "ONE" za pośrednictwem "SIX". Etykiety reprezentują kolejność, w jakiej program osiąga te wiersze kodu.
Poniższy kod przedstawia konspekt 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żda z oznaczonych etykietami lokalizacji "ONE" do "SIX" wyświetla informacje o bieżącym stanie programu. Zostaną wyświetlone następujące dane wyjściowe:
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.
Konfigurowanie programu
Możesz pobrać kod używany w tym temacie z witryny MSDN lub utworzyć go samodzielnie.
Uwaga
Aby uruchomić przykład, na komputerze musi być zainstalowany program Visual Studio 2012 lub nowszy oraz program .NET Framework 4.5 lub nowszy.
Pobieranie programu
Aplikację dla tego tematu można pobrać z async Sample: Control Flow in Async Programs (Przykład asynchroniczny: przepływ sterowania w programach asynchronicznych). Poniższe kroki otwierają i uruchamiają program.
Rozpakuj pobrany plik, a następnie uruchom program Visual Studio.
Na pasku menu wybierz pozycję Plik, Otwórz, Projekt/Rozwiązanie.
Przejdź do folderu zawierającego rozpakowany przykładowy kod, otwórz plik rozwiązania (.sln), a następnie wybierz klucz F5 do skompilowania i uruchomienia projektu.
Samodzielne tworzenie programu
Poniższy projekt Windows Presentation Foundation (WPF) zawiera przykład kodu dla tego tematu.
Aby uruchomić projekt, wykonaj następujące kroki:
Uruchom program Visual Studio.
Na pasku menu wybierz pozycję Plik, Nowy, Projekt.
Zostanie otwarte okno dialogowe Nowy projekt .
W okienku Zainstalowane szablony wybierz pozycję Visual Basic, a następnie wybierz pozycję Aplikacja WPF z listy typów projektów.
Wprowadź
AsyncTracer
jako nazwę projektu, a następnie wybierz przycisk OK .Nowy projekt zostanie wyświetlony w Eksplorator rozwiązań.
W edytorze programu Visual Studio Code wybierz kartę MainWindow.xaml .
Jeśli karta nie jest widoczna, otwórz menu skrótów dla pliku MainWindow.xaml w Eksplorator rozwiązań, a następnie wybierz pozycję Wyświetl kod.
W widoku XAML pliku MainWindow.xaml zastąp kod następującym kodem.
<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>
Proste okno zawierające pole tekstowe i przycisk pojawi się w widoku Projekt mainWindow.xaml.
Dodaj odwołanie dla elementu System.Net.Http.
W Eksplorator rozwiązań otwórz menu skrótów dla MainWindow.xaml.vb, a następnie wybierz pozycję Wyświetl kod.
W MainWindow.xaml.vb zastąp kod następującym kodem.
' 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
Wybierz klawisz F5, aby uruchomić program, a następnie wybierz przycisk Uruchom .
Powinny zostać wyświetlone następujące dane wyjściowe:
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.
Śledzenie programu
Kroki JEDEN i DWA
Dwa pierwsze wiersze wyświetlania śledzą ścieżkę jako startButton_Click
wywołania AccessTheWebAsync
i AccessTheWebAsync
wywołuje metodę GetStringAsync(String)asynchroniczną HttpClient . Na poniższej ilustracji przedstawiono wywołania metody do metody.
Zwracany typ parametru AccessTheWebAsync
i client.GetStringAsync
ma wartość Task<TResult>. W przypadku AccessTheWebAsync
funkcji TResult jest liczbą całkowitą. W przypadku GetStringAsync
elementu TResult jest ciągiem. Aby uzyskać więcej informacji na temat typów zwracanych metod asynchronicznych, zobacz Async Return Types (Visual Basic).
Metoda asynchronizatora zwracająca zadanie zwraca wystąpienie zadania, gdy kontrolka zostanie przesunięta z powrotem do obiektu wywołującego. Kontrolka powraca z metody asynchronicznej do obiektu wywołującego, gdy Await
operator jest napotkany w wywoływanej metodzie lub po zakończeniu wywoływanej metody. Wiersze wyświetlania oznaczone etykietą "TRZY" za pomocą ciągu "SIX" śledzą tę część procesu.
Krok TRZECI
W AccessTheWebAsync
pliku wywoływana jest metoda GetStringAsync(String) asynchroniczna w celu pobrania zawartości docelowej strony internetowej. Kontrolka powraca z client.GetStringAsync
do AccessTheWebAsync
, gdy client.GetStringAsync
zwraca.
Metoda client.GetStringAsync
zwraca zadanie ciągu przypisanego do zmiennej getStringTask
w pliku AccessTheWebAsync
. W poniższym wierszu w przykładowym programie pokazano wywołanie client.GetStringAsync
metody i przypisanie.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
Zadanie można traktować jako obietnicę client.GetStringAsync
, tworząc rzeczywisty ciąg w końcu. W międzyczasie, jeśli AccessTheWebAsync
ma pracę, aby to zrobić, nie zależy od obiecanego ciągu z client.GetStringAsync
, że praca może być kontynuowana podczas client.GetStringAsync
oczekiwania. W tym przykładzie następujące wiersze danych wyjściowych oznaczone etykietą "TRZY" reprezentują możliwość wykonania niezależnej pracy
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
Poniższa instrukcja zawiesza postęp w AccessTheWebAsync
czasie getStringTask
oczekiwania.
Dim urlContents As String = Await getStringTask
Na poniższej ilustracji przedstawiono przepływ sterowania z client.GetStringAsync
do przypisania do getStringTask
i od utworzenia getStringTask
do aplikacji operatora Await.
Wyrażenie await zawiesza się AccessTheWebAsync
do client.GetStringAsync
momentu powrotu. W międzyczasie kontrolka powraca do obiektu wywołującego elementu AccessTheWebAsync
, startButton_Click
.
Uwaga
Zazwyczaj oczekujesz wywołania metody asynchronicznej natychmiast. Na przykład następujące przypisanie może zastąpić poprzedni kod, który tworzy, a następnie czeka na getStringTask
: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")
W tym temacie operator await zostanie zastosowany później w celu uwzględnienia wierszy wyjściowych, które oznaczają przepływ sterowania za pośrednictwem programu.
Krok CZWARTY
Zadeklarowany zwracany typ to AccessTheWebAsync
Task(Of Integer)
. W związku z tym, gdy AccessTheWebAsync
jest zawieszony, zwraca zadanie liczby całkowitej do startButton_Click
. Należy pamiętać, że zwrócone zadanie nie getStringTask
jest . Zwrócone zadanie to nowe zadanie liczb całkowitych, które reprezentuje to, AccessTheWebAsync
co należy wykonać w zawieszonej metodzie . Zadanie jest obietnicą utworzenia AccessTheWebAsync
liczby całkowitej po zakończeniu zadania.
Poniższa instrukcja przypisuje to zadanie do zmiennej getLengthTask
.
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Podobnie jak w programie AccessTheWebAsync
, startButton_Click
może kontynuować pracę, która nie zależy od wyników zadania asynchronicznego (getLengthTask
), dopóki zadanie nie zostanie oczekiwane. Następujące wiersze wyjściowe reprezentują pracę:
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
Postęp w programie startButton_Click
jest zawieszony, gdy getLengthTask
jest oczekiwany. Następująca instrukcja przypisania zawiesza się startButton_Click
do AccessTheWebAsync
momentu ukończenia.
Dim contentLength As Integer = Await getLengthTask
Na poniższej ilustracji strzałki pokazują przepływ sterowania z wyrażenia await do AccessTheWebAsync
przypisania wartości do getLengthTask
, a następnie normalne przetwarzanie w startButton_Click
ciągu do czasu getLengthTask
oczekiwania.
Krok PIĘĆ
Gdy client.GetStringAsync
sygnały, że jest ukończone, przetwarzanie w AccessTheWebAsync
systemie jest zwalniane z zawieszenia i może kontynuować wykonywanie instrukcji await. Następujące wiersze danych wyjściowych reprezentują wznowienie przetwarzania:
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
Operand instrukcji urlContents.Length
return, , jest przechowywany w zadaniu, które AccessTheWebAsync
zwraca. Wyrażenie await pobiera wartość z getLengthTask
elementu w pliku startButton_Click
.
Na poniższej ilustracji przedstawiono transfer kontrolki po client.GetStringAsync
zakończeniu (i getStringTask
).
AccessTheWebAsync
uruchamia polecenie do ukończenia, a kontrolka powraca do startButton_Click
elementu , który oczekuje na ukończenie.
Krok SZEŚĆ
Gdy AccessTheWebAsync
sygnalizuje ukończenie przetwarzania, przetwarzanie może kontynuować wykonywanie instrukcji await w pliku startButton_Async
. W rzeczywistości program nie ma nic więcej do zrobienia.
Następujące wiersze danych wyjściowych reprezentują wznowienie przetwarzania w pliku startButton_Async
:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Wyrażenie await pobiera z getLengthTask
wartości całkowitej, która jest operandem instrukcji return w pliku AccessTheWebAsync
. Poniższa instrukcja przypisuje tej wartości do zmiennej contentLength
.
Dim contentLength As Integer = Await getLengthTask
Na poniższej ilustracji przedstawiono powrót kontrolki z AccessTheWebAsync
do startButton_Click
.