Control Flow in Async Programs (Visual Basic) (Поток управления в асинхронных программах (Visual Basic))
Можно намного проще создавать и обслуживать асинхронные программы с помощью ключевых слов Async
и Await
. Однако при непонимании механизма работы асинхронной программы результаты могут удивить. В этом разделе выполняется трассировка потока управления с помощью простой асинхронной программы, чтобы продемонстрировать переход потока управления от одного метода к другому, включая данные, передаваемые в каждом случае.
Примечание.
Ключевые слова Async
и Await
появились в Visual Studio 2012.
Как правило, вы помечаете методы, содержащие асинхронный код с помощью модификатора Async . В методе, помеченном асинхронным модификатором, можно использовать оператор Await (Visual Basic), чтобы указать, где метод приостанавливает ожидание завершения вызываемого асинхронного процесса. Дополнительные сведения см. в статье асинхронное программирование с помощью Async и Await (Visual Basic).
В следующем примере асинхронные методы используются для загрузки содержимого указанного веб-сайта в виде строки и отображения длины строки. Пример содержит следующие два метода:
startButton_Click
, который вызывает методAccessTheWebAsync
и выводит результат;AccessTheWebAsync
, который загружает содержимое веб-сайта в виде строки и возвращает длину строки.AccessTheWebAsync
использует для загрузки содержимого асинхронный метод HttpClientGetStringAsync(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: 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 перейдите на вкладку MainWindow.xaml .
Если вкладка не отображается, откройте контекстное меню для MainWindow.xaml в обозревателе решений и выберите пункт Просмотреть код.
Замените код в представлении 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
возвращает задачу строки, назначенной переменной getStringTask
в AccessTheWebAsync
. Следующая строка в примере программы демонстрирует вызов client.GetStringAsync
и назначение.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
Можно представить себе задачу как обещание client.GetStringAsync
создать в конечном итоге фактическую строку. В то же время, если AccessTheWebAsync
у него есть работа, которая не зависит от обещанной строки от client.GetStringAsync
, эта работа может продолжаться во время client.GetStringAsync
ожидания. В этом примере следующие строки вывода, которые обозначены как "THREE", представляют возможность сделать независимую работу.
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))
- Walkthrough: Accessing the Web by Using Async and Await (Visual Basic) (Пошаговое руководство. Доступ к веб-сайтам с помощью модификатора Async и оператора Await (Visual Basic))
- Пример асинхронности. Поток управления в асинхронных программах (C# и Visual Basic)