Udostępnij za pośrednictwem


Przepływ sterowania w programach Async (C# i Visual Basic)

Można pisać i łatwiej utrzymać asynchronicznego programy, korzystając z Async i Await słowa kluczowe.Jednak wyniki Zaskakujące Jeśli nie rozumiesz sposób działania programu.W tym temacie śledzi przepływ sterowania za pomocą programu async proste pokazać, kiedy formant przenosi się z jednej metody do innego i jakie informacje są przesyłane za każdym razem.

[!UWAGA]

Async i Await słowa kluczowe zostały wprowadzone w Visual Studio 2012.Aby uzyskać więcej informacji na temat nowych funkcji w tej wersji, zobacz Co nowego w Visual Studio 2012.

Ogólnie rzecz biorąc, możesz oznaczyć metody, które zawierają kod asynchroniczny z Asynchroniczne (Visual Basic) lub async (C#) modyfikator.W metodzie, który jest oznaczony atrybutem modyfikatora komunikacji asynchronicznej, można użyć oczekiwać (Visual Basic) lub czekają na (C#) operatora, aby określić, gdzie metoda wstrzymuje czekać na ukończenie o nazwie procesu asynchronicznego.Aby uzyskać więcej informacji, zobacz Asynchroniczne programowania przy użyciu asynchronicznej i poczekać (C# i Visual Basic).

W poniższym przykładzie użyto metody komunikacji asynchronicznej, aby pobrać zawartość określonej witryny sieci Web jako ciąg znaków i wyświetlić długość ciągu.Przykład zawiera dwie metody.

  • startButton_Click, który wzywa AccessTheWebAsync i wyświetlenie wyniku.

  • AccessTheWebAsync, który pobiera zawartość witryny sieci Web jako ciąg znaków i zwraca długość ciągu.AccessTheWebAsyncużywa asynchronicznej HttpClient metodę, GetStringAsync(String), aby pobrać zawartość.

Numerowane wyświetlanych wierszy pojawiają się na strategicznych punktów w całym programie, aby ułatwić zrozumienie, jak program działa i wyjaśnić, co się stanie, w każdym punkcie, która jest oznaczona.Wyświetlanie linii są oznaczone "Jeden"przez "sześć." Etykiety reprezentują kolejność, w którym program osiąga poniższe linie kodu.

Poniższy kod przedstawia zarys 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 &=
            String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)

    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://msdn.microsoft.com")

        ' THREE
        Dim urlContents As String = Await getStringTask

        ' FIVE
        Return urlContents.Length
    End Function

End Class
public partial class MainWindow : Window
{
    // . . .
    private async void startButton_Click(object sender, RoutedEventArgs e)
    {
        // ONE
        Task<int> getLengthTask = AccessTheWebAsync();

        // FOUR
        int contentLength = await getLengthTask;

        // SIX
        resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
    }


    async Task<int> AccessTheWebAsync()
    {
        // TWO
        HttpClient client = new HttpClient();
        Task<string> getStringTask =
            client.GetStringAsync("https://msdn.microsoft.com");

        // THREE                 
        string urlContents = await getStringTask;

        // FIVE
        return urlContents.Length;
    }
}

Każda z miejsc oznaczonych, "Jeden"przez "SZEŚCIU," Wyświetla informacje o bieżącym stanie programu.Są następujące wyniki.

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.

Wybrana opcja

Kod, który używa w tym temacie można pobrać z sieci MSDN lub można zbudować go samodzielnie.

[!UWAGA]

Aby uruchomić w przykładzie, musisz mieć 2012 Visual Studio, Visual Studio Express 2012 lub 4.5.NET Framework są zainstalowane na komputerze.

Hh873191.collapse_all(pl-pl,VS.110).gifPobierz Program

Możesz pobrać aplikację na ten temat z próbki asynchroniczne: przepływ sterowania w programach asynchroniczne.Następujące kroki otworzyć i uruchomić program.

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

  2. Na pasku menu wybierz kolejno opcje Plik, Otwórz i Projekt/rozwiązanie.

  3. Przejdź do folderu, który przechowuje rozpakowany przykładowy kod, otwórz plik rozwiązania (.sln), a następnie wybierz klawisz F5, aby skompilować i uruchomić projekt.

Hh873191.collapse_all(pl-pl,VS.110).gifZbudować Program sobie

Następujący projekt Windows Presentation Foundation (WPF) zawiera przykładowy kod dla tego tematu.

Aby uruchomić projekt, należy wykonać następujące czynności:

  1. Uruchom program Visual Studio.

  2. Na pasku menu wybierz Plik, Nowy, projekt.

    Zostanie otwarte okno dialogowe Nowy projekt.

  3. W Szablonów okienka, wybierz polecenie języka Visual Basic lub Visual C#, a następnie wybierz polecenie Aplikacji WPF z listy typów projektów.

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

    W Eksploratorze rozwiązań pojawi się nowy projekt.

  5. Wybierz Visual Studio Edytor kodu, MainWindow.xaml kartę.

    Jeśli karta należy otworzyć menu skrótów dla MainWindow.xaml w Solution Explorer, a następnie wybierz polecenie View Code.

  6. W XAML widok na MainWindow.xaml, kod ten należy zastąpić następujący kod.

    <Window
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://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>
    
    <Window
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="https://schemas.microsoft.com/expression/blend/2008" xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="AsyncTracer.MainWindow"
            Title="Control Flow Trace" Height="350" Width="592">
        <Grid>
            <Button x:Name="startButton" Content="Start&#xa;" HorizontalAlignment="Left" Margin="250,10,0,0" VerticalAlignment="Top" Width="75" Height="24"  Click="startButton_Click" d:LayoutOverrides="GridBox"/>
            <TextBox x:Name="resultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="576" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" Grid.ColumnSpan="3"/>
        </Grid>
    </Window>
    

    Proste okno zawierające pola tekstowego i przycisku pojawia się w Projekt widok MainWindow.xaml.

  7. Dodaj odwołanie do System.Net.Http.

  8. W Solution Explorer, otwórz menu skrótów dla MainWindow.xaml.vb lub MainWindow.xaml.cs, a następnie wybierz View Code.

  9. W MainWindow.xaml.vb lub MainWindow.xaml.cs kod ten należy zastąpić następujący kod.

    ' 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://msdn.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
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    // Add a using directive and a reference for System.Net.Http;
    using System.Net.Http;
    
    namespace AsyncTracer
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private async void startButton_Click(object sender, RoutedEventArgs e)
            {
                // The display lines in the example lead you through the control shifts.
                resultsTextBox.Text += "ONE:   Entering startButton_Click.\r\n" +
                    "           Calling AccessTheWebAsync.\r\n";
    
                Task<int> getLengthTask = AccessTheWebAsync();
    
                resultsTextBox.Text += "\r\nFOUR:  Back in startButton_Click.\r\n" +
                    "           Task getLengthTask is started.\r\n" +
                    "           About to await getLengthTask -- no caller to return to.\r\n";
    
                int contentLength = await getLengthTask;
    
                resultsTextBox.Text += "\r\nSIX:   Back in startButton_Click.\r\n" +
                    "           Task getLengthTask is finished.\r\n" +
                    "           Result from AccessTheWebAsync is stored in contentLength.\r\n" +
                    "           About to display contentLength and exit.\r\n";
    
                resultsTextBox.Text +=
                    String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
            }
    
    
            async Task<int> AccessTheWebAsync()
            {
                resultsTextBox.Text += "\r\nTWO:   Entering AccessTheWebAsync.";
    
                // Declare an HttpClient object.
                HttpClient client = new HttpClient();
    
                resultsTextBox.Text += "\r\n           Calling HttpClient.GetStringAsync.\r\n";
    
                // GetStringAsync returns a Task<string>. 
                Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");
    
                resultsTextBox.Text += "\r\nTHREE: Back in AccessTheWebAsync.\r\n" +
                    "           Task getStringTask is started.";
    
                // AccessTheWebAsync can continue to work until getStringTask is awaited.
    
                resultsTextBox.Text +=
                    "\r\n           About to await getStringTask and return a Task<int> to startButton_Click.\r\n";
    
                // Retrieve the website contents when task is complete.
                string urlContents = await getStringTask;
    
                resultsTextBox.Text += "\r\nFIVE:  Back in AccessTheWebAsync." +
                    "\r\n           Task getStringTask is complete." +
                    "\r\n           Processing the return statement." +
                    "\r\n           Exiting from AccessTheWebAsync.\r\n";
    
                return urlContents.Length;
            }
        }
    }
    
  10. Wybierz klawisz F5, aby uruchomić program, a następnie wybierz Start przycisk.

    Powinien pojawić się 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.
    

Program śledzenia

Hh873191.collapse_all(pl-pl,VS.110).gifKroki 1 i 2

Wyświetlanie dwóch pierwszych linii śledzenie ścieżki jako startButton_Click wywołania AccessTheWebAsync, i AccessTheWebAsync wywołania asynchroniczne HttpClient metoda GetStringAsync(String).Poniższy obraz przedstawia wywołania metody metody.

Kroki 1 i 2

Zwracany typ obu AccessTheWebAsync i client.GetStringAsync jest Task<TResult>.Dla AccessTheWebAsync, TResult jest liczbą całkowitą.Dla GetStringAsync, TResult jest ciągiem.Aby uzyskać więcej informacji na temat typami zwracanych metod asynchronicznych, zobacz Typy zwrotu Async (C# i Visual Basic).

Metoda async przekazujących dane zadanie zwróci instancję zadania, podczas kontroli przejście do wywołującego.Sterowania wraca z metody asynchronicznej do miejsca wywołania albo gdy Await lub await napotka operatora w nazwie metody lub kiedy kończy się metodę o nazwie.Wyświetlanie linii, które są oznaczone "Trzy"przez "SZEŚCIU" ślad tej części procesu.

Hh873191.collapse_all(pl-pl,VS.110).gifKrok 3

W AccessTheWebAsync, metod asynchronicznych GetStringAsync(String) jest wywoływana w celu pobrania zawartości strony sieci Web docelowej.Formant zwraca się z client.GetStringAsync do AccessTheWebAsync po client.GetStringAsync zwraca wartość.

client.GetStringAsync Metoda zwraca ciąg, który jest przypisany do zadania getStringTask zmienna in AccessTheWebAsync.Następujący wiersz w programie przykładzie pokazano wywołanie client.GetStringAsync i przypisania.

Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")
Task<string> getStringTask = client.GetStringAsync("https://msdn.microsoft.com");

Można traktować jako promise przez zadania client.GetStringAsync do produkcji rzeczywistej ciąg po pewnym czasie.W międzyczasie Jeśli AccessTheWebAsync ma robić prace, który nie zależy od uzgodnionej ciąg, z client.GetStringAsync, że może kontynuować a client.GetStringAsync czeka.W przykładzie następujące wiersze danych wyjściowych, które są oznaczone jako "Trzy", reprezentują możliwooć niezależną pracę

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

Poniższa instrukcja powoduje zawieszenie postępu w AccessTheWebAsync po getStringTask , należy zachować.

Dim urlContents As String = Await getStringTask
string urlContents = await getStringTask;

Na poniższej ilustracji przedstawiono przepływ sterowania z client.GetStringAsync do przypisania do getStringTask i od utworzenia getStringTask do aplikacji operatora oczekiwać.

Krok 3

Wstrzymuje wyrażenie oczekiwać AccessTheWebAsync do client.GetStringAsync zwraca wartość.W międzyczasie, sterowanie powraca do wywołujący AccessTheWebAsync, startButton_Click.

[!UWAGA]

Zazwyczaj możesz poczekać wywołanie asynchroniczne metoda natychmiast.Na przykład jeden z następujących przydziałów zastąpić poprzedni kod, który tworzy, a następnie czeka na getStringTask:

  • Języka Visual Basic:Dim urlContents As String = Await client.GetStringAsync("https://msdn.microsoft.com")

  • C#: string urlContents = await client.GetStringAsync("https://msdn.microsoft.com");

W tym temacie operator oczekiwać jest stosowana później do wierszy danych wyjściowych, które oznaczają przepływ sterowania za pomocą programu.

Hh873191.collapse_all(pl-pl,VS.110).gifKrok czwarty

Deklarowanym zwracany typ AccessTheWebAsync jest Task(Of Integer) w języku Visual Basic i Task<int> w języku C#.Dlatego też, kiedy AccessTheWebAsync jest zawieszone, zwraca zadania liczby całkowitej w celu startButton_Click.Należy wiedzieć, że zwracane zadanie nie jest getStringTask.Zwrócone zadanie jest nowe zadanie liczby całkowitej reprezentującej, co jeszcze pozostało do zrobienia w metodzie zawieszonych AccessTheWebAsync.Zadanie jest obietnicą z AccessTheWebAsync do produkcji liczbą całkowitą, po wykonaniu zadania.

Następująca instrukcja przypisuje to zadanie, aby getLengthTask zmiennej.

Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Task<int> getLengthTask = AccessTheWebAsync();

Podobnie jak w AccessTheWebAsync, startButton_Click kontynuować pracę, która nie zależy od wyników zadań asynchronicznych (getLengthTask) aż do zadania, należy zachować.Następujące wiersze danych wyjściowych reprezentują tej pracy.

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

Postęp w startButton_Click zostaje zawieszone, kiedy getLengthTask , należy zachować.W następującej instrukcji przypisania zawiesza startButton_Click aż do AccessTheWebAsync została zakończona.

Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;

Na poniższej ilustracji, strzałki pokazują przepływ sterowania z wyrażenia oczekiwać w AccessTheWebAsync do przypisania wartości do getLengthTask, a następnie normalne przetwarzanie w startButton_Click do getLengthTask , należy zachować.

Krok czwarty

Hh873191.collapse_all(pl-pl,VS.110).gifKrok 5

Gdy client.GetStringAsync sygnalizuje, że jest on kompletny przetwarzania w AccessTheWebAsync jest zwolniony z zawieszenia i może kontynuować w ciągu ostatnich instrukcja oczekiwać.Następujące wiersze danych wyjściowych reprezentują na wznowienie przetwarzania.

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

Argument instrukcja return urlContents.Length, jest przechowywany w zadaniu, AccessTheWebAsync zwraca.Wyrażenie oczekiwać pobiera tej wartości od getLengthTask w startButton_Click.

Na poniższej ilustracji przedstawiono przekazanie kontroli po client.GetStringAsync (i getStringTask) nie są zakończone.

Krok 5

AccessTheWebAsyncprowadzi do zakończenia i sterowania wraca do startButton_Click, który jest oczekiwania na zakończenie.

Hh873191.collapse_all(pl-pl,VS.110).gifKrok 6

Gdy AccessTheWebAsync sygnalizuje, że zakończenie przetwarzania można nadal w ciągu ostatnich instrukcję oczekiwać w startButton_Async.W rzeczywistości, program nie ma nic więcej robić.

Następujące wiersze danych wyjściowych reprezentują na wznowienie przetwarzania w 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 oczekiwać pobiera z getLengthTask wartość całkowitą, która jest operand instrukcja return w AccessTheWebAsync.Następująca instrukcja przypisuje wartości do contentLength zmiennej.

Dim contentLength As Integer = Await getLengthTask
int contentLength = await getLengthTask;

Na poniższej ilustracji przedstawiono powrót sterowania z AccessTheWebAsync do startButton_Click.

Krok 6

Zobacz też

Zadania

Instruktaż: Dostęp do sieci Web za pomocą transmisji asynchronicznej i poczekać (C# i Visual Basic)

Wskazówki: Korzystanie z debugera i metod asynchronicznych

Koncepcje

Asynchroniczne programowania przy użyciu asynchronicznej i poczekać (C# i Visual Basic)

Typy zwrotu Async (C# i Visual Basic)

Inne zasoby

Próbka asynchroniczne: Przepływ sterowania w programach Async (C# i Visual Basic)