Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
С помощью ключевых слов Async
и Await
можно легче создавать и поддерживать асинхронные программы. Однако результаты могут удивить вас, если вы не понимаете, как работает ваша программа. В этом разделе отслеживается поток управления с помощью простой асинхронной программы, чтобы показать, когда элемент управления перемещается из одного метода в другой и какие сведения передаются каждый раз.
Замечание
Ключевые слова Async
и Await
были введены в Visual Studio 2012.
Как правило, вы помечаете методы, содержащие асинхронный код с помощью модификатора Async . В методе, помеченном асинхронным модификатором, можно использовать оператор Await (Visual Basic), чтобы указать, где метод приостанавливает ожидание завершения вызываемого асинхронного процесса. Дополнительные сведения см. в статье асинхронное программирование с помощью Async и Await (Visual Basic).
В следующем примере используются асинхронные методы для скачивания содержимого указанного веб-сайта в виде строки и отображения длины строки. Пример содержит следующие два метода.
startButton_Click
, который вызываетAccessTheWebAsync
и отображает результат.AccessTheWebAsync
, который скачивает содержимое веб-сайта в виде строки и возвращает длину строки.AccessTheWebAsync
использует асинхронный HttpClient метод, GetStringAsync(String)чтобы скачать содержимое.
Нумерованные линии отображения отображаются в стратегических точках по всей программе, чтобы понять, как выполняется программа, и объяснить, что происходит в каждой точке, помеченной. Отображаемые строки обозначены как "ONE" по "ШЕСТЬ". Метки представляют порядок, в котором программа достигает этих строк кода.
В следующем коде показана структура программы.
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
В каждом из помеченных мест с надписями "ONE" до "SIX" отображается информация о текущем состоянии программы. Выводятся следующие выходные данные:
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.
Настройка программы
Вы можете скачать код, который этот раздел использует из MSDN, или создать его самостоятельно.
Замечание
Чтобы запустить пример, необходимо установить Visual Studio 2012 или более поздней версии и .NET Framework 4.5 или более поздней версии на компьютере.
Скачивание программы
Вы можете скачать приложение по этой теме из примера Async: управление потоком в асинхронных программах. Эти шаги открывают и запускают программу.
Распакуйте скачанный файл и запустите Visual Studio.
В строке меню выберите "Файл", "Открыть", "Проект или решение".
Перейдите в папку с распакованным примером кода, откройте файл решения (.sln), а затем выберите ключ F5 для сборки и запуска проекта.
Создание программы самостоятельно
Следующий проект Windows Presentation Foundation (WPF) содержит пример кода для этого раздела.
Чтобы запустить проект, выполните следующие действия.
Запустите Visual Studio.
В строке меню выберите "Файл", "Создать", "Проект".
Откроется диалоговое окно "Новый проект ".
В области установленных шаблонов выберите Visual Basic и выберите приложение WPF из списка типов проектов.
Введите
AsyncTracer
имя проекта и нажмите кнопку "ОК ".Новый проект появится в обозревателе решений.
В редакторе Visual Studio Code выберите вкладку MainWindow.xaml .
Если вкладка не отображается, откройте контекстное меню mainWindow.xaml в обозревателе решений и выберите команду View Code.
В представлении XAML MainWindow.xaml замените код следующим кодом.
<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>
Простое окно, содержащее текстовое поле и кнопку, отображается в представлении дизайна MainWindow.xaml.
Добавьте ссылку для System.Net.Http.
В обозревателе решений откройте контекстное меню для MainWindow.xaml.vb и выберите команду "Просмотреть код".
В MainWindow.xaml.vb замените код следующим кодом.
' 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
Нажмите клавишу F5, чтобы запустить программу, а затем нажмите кнопку Start .
Должны появиться следующие выходные данные:
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.
Трассировка программы
Шаги ОДИН и ДВА
Первые две строки экрана трассируют путь, где startButton_Click
вызывает AccessTheWebAsync
, а AccessTheWebAsync
вызывает асинхронный метод HttpClientGetStringAsync(String). На следующем рисунке показаны переходы от одного метода к другому.
Возвращаемый тип AccessTheWebAsync
и client.GetStringAsync
— Task<TResult>. Для AccessTheWebAsync
, TResult является целым числом. Для GetStringAsync
, TResult является строкой. Дополнительные сведения о типах возврата асинхронного метода см. в статье Async Return Types (Visual Basic).
Асинхронный метод, возвращающий задачу, возвращает экземпляр задачи, когда управление возвращается вызывающему объекту. Управление возвращается из асинхронного метода к вызывающей стороне либо при обнаружении оператора Await
в вызываемом методе, либо при завершении вызываемого метода. Отображаемые строки, помеченные как "ТРИ" и "ШЕСТЬ", трассируют эту часть процесса.
Шаг ТРИ
В AccessTheWebAsync
вызывается асинхронный метод GetStringAsync(String) для загрузки содержимого целевой веб-страницы. Управление возвращается от client.GetStringAsync
к AccessTheWebAsync
, когда происходит возврат из client.GetStringAsync
.
Метод client.GetStringAsync
возвращает задачу типа string, которая назначена переменной getStringTask
в AccessTheWebAsync
. В следующей строке в примере программы показан вызов client.GetStringAsync
и назначение.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
Вы можете рассматривать задачу как обещание со стороны client.GetStringAsync
в конце концов создать фактическую строку. В то же время, если у AccessTheWebAsync
есть работа, которая не зависит от обещанной строки от client.GetStringAsync
, эта работа может продолжаться, пока client.GetStringAsync
ожидает. В примере строки выходных данных, обозначенные как "ТРИ", представляют собой возможность для выполнения самостоятельной работы.
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
Следующее утверждение приостанавливает прогресс в AccessTheWebAsync
, когда getStringTask
ожидается.
Dim urlContents As String = Await getStringTask
На следующем рисунке показан поток управления от client.GetStringAsync
до присваивания getStringTask
, а затем от создания getStringTask
до применения оператора Await.
Выражение await приостанавливается AccessTheWebAsync
до тех пор, пока client.GetStringAsync
не возвращает. В то же время контроль возвращается вызывающему объекту AccessTheWebAsync
, startButton_Click
.
Замечание
Обычно после вызова асинхронного метода ожидание начинается сразу. Например, следующее назначение может заменить предыдущий код, который создает, а затем ожидает getStringTask
: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")
В этом разделе оператор await применяется позже, чтобы учитывать выходные строки, которые обозначают поток управления через программу.
Шаг ЧЕТЫРЕ
Объявленный тип возвращаемого значения AccessTheWebAsync
— Task(Of Integer)
. Поэтому, когда AccessTheWebAsync
приостанавливается, она возвращает задачу, которая выдает целочисленное значение startButton_Click
. Вы должны понимать, что возвращаемая задача не getStringTask
. Возвращаемая задача — это новая задача целого числа, представляющая то, что осталось сделать в приостановленном методе AccessTheWebAsync
. Задача — это обещание от AccessTheWebAsync
создать целое число, когда задача будет завершена.
Следующая инструкция назначает эту задачу переменной getLengthTask
.
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Как и в случае AccessTheWebAsync
, startButton_Click
можно продолжать работу, которая не зависит от результатов асинхронной задачи (getLengthTask
) до ожидания задачи. Следующие выходные строки представляют собой следующую работу:
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
Продвижение startButton_Click
приостанавливается при ожидании getLengthTask
. Следующий оператор присваивания приостанавливает действие startButton_Click
до завершения AccessTheWebAsync
.
Dim contentLength As Integer = Await getLengthTask
На следующем рисунке стрелки показывают поток управления от выражения await в AccessTheWebAsync
к назначению значения getLengthTask
, а затем обычная обработка в startButton_Click
продолжается, пока getLengthTask
не будет ожидаемым.
Шаг ПЯТЬ
Когда client.GetStringAsync
сигнализирует о завершении, обработка AccessTheWebAsync
освобождается от приостановки и может продолжаться после инструкции await. Следующие строки выходных данных представляют возобновление обработки:
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
Операнд инструкции return urlContents.Length
хранится в задаче, которую возвращает AccessTheWebAsync
. Выражение await извлекает это значение из getLengthTask
в startButton_Click
.
На следующем рисунке показана передача управления после завершения client.GetStringAsync
и getStringTask
.
AccessTheWebAsync
выполняется до полного завершения, и элемент управления переходит к startButton_Click
, который находится в ожидании завершения.
Шаг ШЕСТЬ
Когда AccessTheWebAsync
сигнализирует о завершении, обработка может продолжиться после инструкции await в startButton_Async
. На самом деле, программе больше ничего не нужно делать.
Следующие строки выходных данных представляют возобновление обработки в startButton_Async
:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
Выражение await извлекает целочисленное значение из getLengthTask
, которое является операндом инструкции return в AccessTheWebAsync
. Следующая инструкция назначает это значение переменной contentLength
.
Dim contentLength As Integer = Await getLengthTask
На изображении ниже показана передача контроля от AccessTheWebAsync
к startButton_Click
.
См. также
- Асинхронное программирование с использованием ключевых слов Async и Await (Visual Basic)
- Async Return Types (Visual Basic) (Типы возвращаемых значений Async (Visual Basic))
- Пошаговое руководство. Доступ к Интернету с помощью Async и Await (Visual Basic)
- Пример async: поток управления в асинхронных программах (C# и Visual Basic)