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.
Pobierz 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.
Rozpakuj pobrany plik, a następnie uruchom Visual Studio 2012.
Na pasku menu wybierz kolejno opcje Plik, Otwórz i Projekt/rozwiązanie.
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.
Zbudować 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:
Uruchom program Visual Studio.
Na pasku menu wybierz Plik, Nowy, projekt.
Zostanie otwarte okno dialogowe Nowy projekt.
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.
Wprowadź AsyncTracer jako nazwę projektu, a następnie wybierz polecenie OK przycisk.
W Eksploratorze rozwiązań pojawi się nowy projekt.
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.
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
" 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.
Dodaj odwołanie do System.Net.Http.
W Solution Explorer, otwórz menu skrótów dla MainWindow.xaml.vb lub MainWindow.xaml.cs, a następnie wybierz View Code.
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; } } }
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
Kroki 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.
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.
Krok 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ć.
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.
Krok 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 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.
AccessTheWebAsyncprowadzi do zakończenia i sterowania wraca do startButton_Click, który jest oczekiwania na zakończenie.
Krok 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.
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)