Udostępnij za pośrednictwem


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łuje AccessTheWebAsync 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.

  1. Rozpakuj pobrany plik, a następnie uruchom program Visual Studio.

  2. Na pasku menu wybierz pozycję Plik, Otwórz, Projekt/Rozwiązanie.

  3. 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:

  1. Uruchom program Visual Studio.

  2. Na pasku menu wybierz pozycję Plik, Nowy, Projekt.

    Zostanie otwarte okno dialogowe Nowy projekt .

  3. W okienku Zainstalowane szablony wybierz pozycję Visual Basic, a następnie wybierz pozycję Aplikacja WPF z listy typów projektów.

  4. Wprowadź AsyncTracer jako nazwę projektu, a następnie wybierz przycisk OK .

    Nowy projekt zostanie wyświetlony w Eksplorator rozwiązań.

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

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

  7. Dodaj odwołanie dla elementu System.Net.Http.

  8. W Eksplorator rozwiązań otwórz menu skrótów dla MainWindow.xaml.vb, a następnie wybierz pozycję Wyświetl kod.

  9. 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
    
  10. 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 AccessTheWebAsynci AccessTheWebAsync wywołuje metodę GetStringAsync(String)asynchroniczną HttpClient . Na poniższej ilustracji przedstawiono wywołania metody do metody.

Steps ONE and TWO

Zwracany typ parametru AccessTheWebAsync i client.GetStringAsync ma wartość Task<TResult>. W przypadku AccessTheWebAsyncfunkcji TResult jest liczbą całkowitą. W przypadku GetStringAsyncelementu 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 AccessTheWebAsyncpliku 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.

Step THREE

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 AccessTheWebAsyncTask(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 getStringTaskjest . Zwrócone zadanie to nowe zadanie liczb całkowitych, które reprezentuje to, AccessTheWebAsyncco 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.

Step FOUR

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.Lengthreturn, , 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).

Step FIVE

AccessTheWebAsync uruchamia polecenie do ukończenia, a kontrolka powraca do startButton_Clickelementu , 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.

Step SIX

Zobacz też