Freigeben über


Steuerungsfluss in Async-Programmen (Visual Basic)

Sie können asynchrone Programme einfacher schreiben und verwalten, indem Sie die Async Schlüsselwörter verwenden Await . Die Ergebnisse können Sie jedoch überraschen, wenn Sie nicht verstehen, wie Ihr Programm funktioniert. In diesem Thema wird der Ablauf der Steuerung über ein einfaches asynchrones Programm verfolgt, um Ihnen zu zeigen, wann das Steuerelement von einer Methode zu einer anderen wechselt und welche Informationen jedes Mal übertragen werden.

Hinweis

Die Async Schlüsselwörter und Await Schlüsselwörter wurden in Visual Studio 2012 eingeführt.

Im Allgemeinen markieren Sie Methoden, die asynchronen Code mit dem Asynchronen Modifizierer enthalten. In einer Methode, die mit einem asynchronen Modifizierer gekennzeichnet ist, können Sie einen Await -Operator (Visual Basic) verwenden, um anzugeben, wo die Methode angehalten wird, bis ein aufgerufener asynchroner Prozess abgeschlossen ist. Weitere Informationen finden Sie unter Asynchrone Programmierung mit Async und Await (Visual Basic).

Im folgenden Beispiel werden asynchrone Methoden verwendet, um den Inhalt einer angegebenen Website als Zeichenfolge herunterzuladen und die Länge der Zeichenfolge anzuzeigen. Das Beispiel enthält die folgenden beiden Methoden.

  • startButton_Click, das AccessTheWebAsync aufruft und das Ergebnis anzeigt.

  • AccessTheWebAsync, die den Inhalt einer Website als Zeichenfolge herunterlädt und die Länge der Zeichenfolge zurückgibt. AccessTheWebAsync verwendet eine asynchrone HttpClient Methode, GetStringAsync(String)um den Inhalt herunterzuladen.

Nummerierte Anzeigelinien werden an strategischen Punkten im gesamten Programm angezeigt, um zu verstehen, wie das Programm ausgeführt wird, und zu erläutern, was an jedem markierten Punkt passiert. Die Anzeigelinien sind als "ONE" bis "SIX" beschriftet. Diese Beschriftungen repräsentieren die Reihenfolge, in der das Programm diese Codezeilen erreicht.

Der folgende Code zeigt eine Gliederung des Programms.

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

Jeder der bezeichneten Speicherorte, "ONE" bis "SIX", zeigt Informationen zum aktuellen Status des Programms an. Es wird die folgende Ausgabe generiert:

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.

Einrichten des Programms

Sie können den Code herunterladen, den dieses Thema von MSDN verwendet, oder Sie können ihn selbst erstellen.

Hinweis

Zum Ausführen des Beispiels müssen Sie Visual Studio 2012 oder höher und .NET Framework 4.5 oder höher auf Ihrem Computer installiert haben.

Programm herunterladen

Sie können die Anwendung für dieses Thema aus Async-Beispiel: Steuerungsfluss in Async-Programmen herunterladen. Die folgenden Schritte öffnen und führen das Programm aus.

  1. Entpacken Sie die heruntergeladene Datei, und starten Sie Visual Studio.

  2. Wählen Sie auf der Menüleiste "Datei", "Öffnen", "Projekt/Projektmappe" aus.

  3. Navigieren Sie zu dem Ordner, der den entzippten Beispielcode enthält, öffnen Sie die Projektmappendatei (.sln), und wählen Sie dann den F5-Schlüssel aus, um das Projekt zu erstellen und auszuführen.

Erstellen Sie das Programm selbst

Das folgende Windows Presentation Foundation (WPF)-Projekt enthält das Codebeispiel für dieses Thema.

Führen Sie zum Ausführen des Projekts die folgenden Schritte aus:

  1. Starten Sie Visual Studio.

  2. Klicken Sie in der Menüleiste auf Datei, Neu, Projekt.

    Das Dialogfeld "Neues Projekt " wird geöffnet.

  3. Wählen Sie im Bereich "Installierte Vorlagen " Visual Basic und dann "WPF-Anwendung " aus der Liste der Projekttypen aus.

  4. Geben Sie AsyncTracer den Namen des Projekts ein, und wählen Sie dann die Schaltfläche "OK " aus.

    Das neue Projekt wird im Projektmappen-Explorer angezeigt.

  5. Wählen Sie im Visual Studio Code-Editor die Registerkarte "MainWindow.xaml " aus.

    Wenn die Registerkarte nicht sichtbar ist, öffnen Sie das Kontextmenü für "MainWindow.xaml" im Projektmappen-Explorer, und wählen Sie dann "Code anzeigen" aus.

  6. Ersetzen Sie in der XAML-Ansicht von "MainWindow.xaml" den Code durch den folgenden 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>
    

    Ein einfaches Fenster mit einem Textfeld und einer Schaltfläche wird in der Entwurfsansicht von "MainWindow.xaml" angezeigt.

  7. Fügen Sie einen Verweis für System.Net.Http.

  8. Öffnen Sie im Lösungs-Explorer das Kontextmenü für MainWindow.xaml.vb, und wählen Sie dann Code anzeigen aus.

  9. Ersetzen Sie in MainWindow.xaml.vb den Code durch den folgenden 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
    
  10. Wählen Sie die F5-TASTE aus, um das Programm auszuführen, und wählen Sie dann die Schaltfläche " Start " aus.

    Die folgende Ausgabe sollte angezeigt werden:

    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.
    

Ablaufverfolgung für das Programm durchführen

Schritte 1 und 2

Die ersten beiden Anzeigezeilen verfolgen den Pfad, wenn startButton_ClickAccessTheWebAsync aufruft und AccessTheWebAsync die asynchrone HttpClient Methode GetStringAsync(String) aufruft. In der folgenden Abbildung werden die Aufrufe von Methode zu Methode beschrieben.

Schritte ONE und TWO

Der Rückgabetyp von beiden AccessTheWebAsync und client.GetStringAsync ist Task<TResult>. Für AccessTheWebAsync, TResult ist eine ganze Zahl. Für GetStringAsync ist TResult eine Zeichenfolge. Weitere Informationen zu asynchronen Methoden-Rückgabetypen finden Sie unter Async-Rückgabetypen (Visual Basic).

Eine asynchrone Methode, die eine Aufgabe zurückgibt, gibt eine Aufgabeninstanz zurück, wenn die Steuerung wieder zum Aufrufer zurückwechselt. Die Kontrolle kehrt aus einer asynchronen Methode zu ihrem Aufrufer zurück, entweder wenn ein Await-Operator in der aufgerufenen Methode auftritt oder wenn die aufgerufene Methode endet. Die Anzeigezeilen, die mit "DREI" bis "SECHS" bezeichnet werden, verfolgen diesen Teil des Prozesses.

Schritt 3

In AccessTheWebAsync, die asynchrone Methode GetStringAsync(String) wird aufgerufen, um den Inhalt der Zielwebseite herunterzuladen. Die Kontrolle wechselt von client.GetStringAsync zu AccessTheWebAsync, wenn client.GetStringAsync zurückkehrt.

Die client.GetStringAsync-Methode gibt einen Task vom Typ string zurück, der der getStringTask-Variablen in AccessTheWebAsync zugewiesen ist. Die folgende Zeile im Beispielprogramm zeigt den Aufruf von client.GetStringAsync und die Zuweisung.

Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")

Sie können sich die Aufgabe als Zusage von client.GetStringAsync vorstellen, schließlich eine tatsächliche Zeichenfolge zu erzeugen. Falls AccessTheWebAsync Arbeit zu erledigen hat, die nicht von der versprochenen Zeichenfolge aus client.GetStringAsync abhängt, kann diese Arbeit fortgesetzt werden, während client.GetStringAsync wartet. Im Beispiel bieten die folgenden, mit „THREE“ bezeichneten Ausgabezeilen die Gelegenheit, um unabhängige Aufgaben auszuführen.

THREE: Back in AccessTheWebAsync.
           Task getStringTask is started.
           About to await getStringTask & return a Task<int> to startButton_Click.

Durch die folgende Anweisung wird die Ausführung in AccessTheWebAsync angehalten, wenn getStringTask erwartet wird.

Dim urlContents As String = Await getStringTask

Die folgende Abbildung zeigt den Kontrollfluss von client.GetStringAsync bis zur Zuweisung an getStringTask und von der Erstellung von getStringTask bis zur Anwendung eines Await-Operators.

Schritt 3

Durch den await-Ausdruck wird AccessTheWebAsync angehalten, bis client.GetStringAsync zurückgegeben wird. In der Zwischenzeit kehrt die Steuerung zum Aufrufer von AccessTheWebAsync, startButton_Click, zurück.

Hinweis

In der Regel warten Sie sofort auf den Aufruf einer asynchronen Methode. Die folgende Zuweisung könnte z. B. den vorherigen Code ersetzen, der erstellt und anschließend abwartet getStringTask: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")

In diesem Thema wird der await-Operator später angewendet, um die Ausgabezeilen anzupassen, die die Ablaufsteuerung durch das Programm markieren.

Schritt 4

Der deklarierte Rückgabetyp ist AccessTheWebAsyncTask(Of Integer). Wenn AccessTheWebAsync angehalten wird, wird daher eine Ganzzahlaufgabe an startButton_Click zurückgegeben. Sie sollten verstehen, dass die zurückgegebene Aufgabe nicht getStringTaskist. Der zurückgegebene Vorgang ist eine neue Aufgabe mit ganzzahliger Zahl, die angibt, was in der angehaltenen Methode AccessTheWebAsyncnoch zu erledigen ist. Die Aufgabe ist eine Zusage von AccessTheWebAsync, eine ganze Zahl zu erzeugen, wenn die Aufgabe abgeschlossen wird.

Die folgende Anweisung weist diese Aufgabe der getLengthTask Variablen zu.

Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()

Wie in AccessTheWebAsync, kann startButton_Click seine Arbeit fortsetzen, die nicht von den Ergebnissen der asynchronen Aufgabe (getLengthTask) abhängt, bis die Aufgabe abgewartet wird. Die folgenden Ausgabezeilen stellen diese Aufgaben dar:

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

Fortschritt in startButton_Click wird angehalten, während getLengthTask erwartet wird. Durch die folgende Zuweisungsanweisung wird startButton_Click angehalten, bis AccessTheWebAsync abgeschlossen ist.

Dim contentLength As Integer = Await getLengthTask

In der folgenden Abbildung veranschaulichen die Pfeile die Ablaufsteuerung vom await-Ausdruck in AccessTheWebAsync zur Zuweisung eines Werts an getLengthTask, gefolgt von normaler Verarbeitung in startButton_Click bis getLengthTask erwartet wird.

Schritt VIER

Schritt FÜNF

Wenn client.GetStringAsync signalisiert, dass die Verarbeitung abgeschlossen ist, wird die Verarbeitung in AccessTheWebAsync aus der Unterbrechung freigegeben und kann über die await-Anweisung hinaus fortgesetzt werden. Die folgenden Ausgabezeilen stellen die Wiederaufnahme der Verarbeitung dar:

FIVE:  Back in AccessTheWebAsync.
           Task getStringTask is complete.
           Processing the return statement.
           Exiting from AccessTheWebAsync.

Der Operand der return-Anweisung (urlContents.Length) wird in der Aufgabe gespeichert, die AccessTheWebAsync zurückgibt. Der Await-Ausdruck ruft diesen Wert aus getLengthTask innerhalb startButton_Click ab.

Die folgende Abbildung zeigt die Übertragung der Kontrolle, nachdem client.GetStringAsync (und getStringTask) abgeschlossen sind.

Schritt FÜNF

AccessTheWebAsync wird bis zum Abschluss ausgeführt und die Steuerung kehrt zu startButton_Click zurück, das den Abschluss erwartet.

Schritt SIX

Wenn AccessTheWebAsync signalisiert, dass der Vorgang abgeschlossen ist, kann die Verarbeitung über die Await-Anweisung hinaus fortgesetzt werden.startButton_Async Tatsächlich hat das Programm nichts mehr zu tun.

Die folgenden Ausgabezeilen stellen die Wiederaufnahme der Verarbeitung in startButton_Async dar.

SIX:   Back in startButton_Click.
           Task getLengthTask is finished.
           Result from AccessTheWebAsync is stored in contentLength.
           About to display contentLength and exit.

Der 'await'-Ausdruck ruft den ganzzahligen Wert aus getLengthTask ab, der der Operand der Rückgabeanweisung in AccessTheWebAsync ist. Mit der folgenden Anweisung wird dieser Wert der contentLength Variablen zugewiesen.

Dim contentLength As Integer = Await getLengthTask

Die folgende Abbildung zeigt die Rückkehr der Steuerung von AccessTheWebAsync zu startButton_Click.

Schritt SECHS

Siehe auch