Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Puede escribir y mantener programas asincrónicos con mayor facilidad mediante las Async
palabras clave y Await
. Sin embargo, los resultados pueden sorprenderle si no entiende cómo funciona su programa. En este tema se realiza un seguimiento del flujo de control a través de un programa asincrónico sencillo para mostrar cuándo el control pasa de un método a otro y qué información se transfiere cada vez.
Nota:
Las Async
palabras clave y Await
se introdujeron en Visual Studio 2012.
En general, se marcan métodos que contienen código asincrónico con el modificador Async . En un método marcado con un modificador asincrónico, puede usar un operador Await (Visual Basic) para especificar dónde se pausa el método para esperar a que se complete un proceso asincrónico llamado. Para obtener más información, vea Programación asincrónica con Async y Await (Visual Basic).
En el ejemplo siguiente se usan métodos asincrónicos para descargar el contenido de un sitio web especificado como una cadena y mostrar la longitud de la cadena. El ejemplo contiene los dos métodos siguientes.
startButton_Click
, que llama aAccessTheWebAsync
y muestra el resultado.AccessTheWebAsync
, que descarga el contenido de un sitio web como una cadena y devuelve la longitud de la cadena.AccessTheWebAsync
usa un método asincrónico HttpClient , GetStringAsync(String), para descargar el contenido.
Las líneas de visualización numeradas aparecen en puntos estratégicos en todo el programa para ayudarle a comprender cómo se ejecuta el programa y explicar lo que sucede en cada punto marcado. Las líneas de presentación se etiquetan como "ONE" a "SIX". Las etiquetas representan el orden en el que el programa alcanza estas líneas de código.
El código siguiente muestra un esquema del programa.
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
Cada una de las ubicaciones etiquetadas, "ONE" a "SIX", muestra información sobre el estado actual del programa. Se genera la siguiente salida:
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.
Configurar el programa
Puede descargar el código que usa este tema desde MSDN o puede compilarlo usted mismo.
Nota:
Para ejecutar el ejemplo, debe tener Visual Studio 2012 o versiones posteriores y .NET Framework 4.5 o posterior instalado en el equipo.
Descargar el programa
Puede descargar la aplicación para este tema desde Async Sample: Control Flow in Async Programs( Ejemplo asincrónico: Flujo de control en programas asincrónicos). Los pasos siguientes abren y ejecutan el programa.
Descomprima el archivo descargado y, a continuación, inicie Visual Studio.
En la barra de menús, elija Archivo, Abrir, Proyecto o solución.
Vaya a la carpeta que contiene el código de ejemplo descomprimido, abra el archivo de solución (.sln) y, a continuación, elija la clave F5 para compilar y ejecutar el proyecto.
Crear el programa usted mismo
El siguiente proyecto de Windows Presentation Foundation (WPF) contiene el ejemplo de código de este tema.
Para ejecutar el proyecto, realice los pasos siguientes:
Inicie Visual Studio.
En la barra de menús, elija Archivo, Nuevo, Proyecto.
Se abre el cuadro de diálogo Nuevo proyecto .
En el panel Plantillas instaladas , elija Visual Basic y, a continuación, elija Aplicación WPF en la lista de tipos de proyecto.
Escriba
AsyncTracer
como nombre del proyecto y, a continuación, elija el botón Aceptar .El proyecto nuevo aparece en el Explorador de soluciones.
En el Editor de código de Visual Studio, elija la pestaña MainWindow.xaml .
Si la pestaña no está visible, abra el menú contextual de MainWindow.xaml en el Explorador de soluciones y elija Ver código.
En la vista XAML de MainWindow.xaml, reemplace el código por el código siguiente.
<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>
Una ventana simple que contiene un cuadro de texto y un botón aparece en la vista Diseño de MainWindow.xaml.
Agregue una referencia para System.Net.Http.
En el Explorador de soluciones, abra el menú contextual de MainWindow.xaml.vb y seleccione Ver código.
En MainWindow.xaml.vb , reemplace el código por el código siguiente.
' 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
Presione la tecla F5 para ejecutar el programa y elija el botón Inicio .
Debería aparecer la siguiente salida:
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.
Seguimiento del programa
Pasos UNO y DOS
Las dos primeras líneas trazan el camino cuando startButton_Click
llama a AccessTheWebAsync
, y AccessTheWebAsync
llama al método asincrónico HttpClientGetStringAsync(String). En la siguiente imagen se describen las llamadas de método a método.
El tipo de retorno de ambos AccessTheWebAsync
y client.GetStringAsync
es Task<TResult>. Para AccessTheWebAsync
, TResult es un entero. Para GetStringAsync
, TResult es una cadena. Para obtener más información sobre los tipos de retorno de métodos asincrónicos, vea Tipos de retorno asincrónicos (Visual Basic).
Un método asincrónico que devuelve una tarea retorna una instancia de tarea cuando el control vuelve al llamador. El control regresa de un método asincrónico al método que lo llamó cuando se encuentra un operador Await
en el método llamado o cuando finaliza el método llamado. Las líneas de visualización que están etiquetadas como "THREE" a "SIX" siguen esta parte del proceso.
Paso TRES
En AccessTheWebAsync
, se llama al método GetStringAsync(String) asincrónico para descargar el contenido de la página web de destino. El control vuelve de client.GetStringAsync
a AccessTheWebAsync
cuando client.GetStringAsync
retorna.
El client.GetStringAsync
método devuelve una tarea de cadena que se asigna a la getStringTask
variable en AccessTheWebAsync
. La siguiente línea en el programa de ejemplo muestra la llamada a client.GetStringAsync
y la asignación.
Dim getStringTask As Task(Of String) = client.GetStringAsync("https://learn.microsoft.com")
Puede considerar la tarea como una promesa de client.GetStringAsync
de generar una cadena real. Mientras tanto, si AccessTheWebAsync
tiene trabajo pendiente que no depende de la cadena prometida de client.GetStringAsync
, ese trabajo puede continuar mientras client.GetStringAsync
espera. En el ejemplo, las siguientes líneas de salida, que se etiquetan como "THREE", representan la oportunidad de realizar un trabajo independiente.
THREE: Back in AccessTheWebAsync.
Task getStringTask is started.
About to await getStringTask & return a Task<int> to startButton_Click.
La siguiente instrucción suspende el progreso en AccessTheWebAsync
cuando se espera a getStringTask
.
Dim urlContents As String = Await getStringTask
En la imagen siguiente se muestra el flujo de control desde client.GetStringAsync
hasta la asignación hacia getStringTask
y desde la creación de getStringTask
a la aplicación de un operador Await.
La expresión await suspende AccessTheWebAsync
hasta que se devuelva client.GetStringAsync
. Mientras tanto, el control vuelve al llamador de AccessTheWebAsync
, startButton_Click
.
Nota:
Normalmente se espera la llamada a un método asincrónico de forma inmediata. Por ejemplo, la siguiente asignación podría reemplazar el código anterior que crea y luego espera getStringTask
: Dim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")
En este tema, el operador await se aplica más adelante para dar cabida a las líneas de salida que marcan el flujo de control a través del programa.
Paso CUATRO
El tipo de valor devuelto declarado de AccessTheWebAsync
es Task(Of Integer)
. Por lo tanto, cuando AccessTheWebAsync
se suspende, devuelve una tarea de entero a startButton_Click
. Debe entender que la tarea devuelta no es getStringTask
. La tarea devuelta es una nueva tarea de entero que representa lo que queda por hacer en el método suspendido, AccessTheWebAsync
. La tarea es una promesa de AccessTheWebAsync
para generar un entero cuando se completa la tarea.
La instrucción siguiente asigna esta tarea a la getLengthTask
variable .
Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
Como en AccessTheWebAsync
, startButton_Click
puede continuar con el trabajo que no depende de los resultados de la tarea asincrónica (getLengthTask
) hasta que se espere la tarea. Las siguientes líneas de salida representan ese trabajo:
FOUR: Back in startButton_Click.
Task getLengthTask is started.
About to await getLengthTask -- no caller to return to.
El progreso de startButton_Click
se suspende cuando se espera getLengthTask
. La siguiente instrucción de asignación suspende startButton_Click
hasta que concluya AccessTheWebAsync
.
Dim contentLength As Integer = Await getLengthTask
En la siguiente ilustración, las flechas muestran el flujo de control desde la expresión await en AccessTheWebAsync
hasta la asignación de un valor a getLengthTask
, seguido del procesamiento normal en startButton_Click
hasta que se espera a getLengthTask
.
Paso CINCO
Cuando client.GetStringAsync
indica que ha finalizado, el procesamiento de AccessTheWebAsync
sale de la suspensión y puede continuar una vez superada la instrucción await. Las siguientes líneas de salida representan la reanudación del procesamiento:
FIVE: Back in AccessTheWebAsync.
Task getStringTask is complete.
Processing the return statement.
Exiting from AccessTheWebAsync.
El operando de la instrucción return, urlContents.Length
, se almacena en la tarea que AccessTheWebAsync
devuelve. La expresión await recupera ese valor de getLengthTask
en startButton_Click
.
En la imagen siguiente se muestra la transferencia del control después de que client.GetStringAsync
(y getStringTask
) se completen.
AccessTheWebAsync
se ejecuta hasta el final y el control vuelve a startButton_Click
, que espera la finalización.
Paso SEIS
Cuando AccessTheWebAsync
indica que ha finalizado, el procesamiento puede continuar una vez superada la instrucción await en startButton_Async
. De hecho, el programa no tiene nada más que hacer.
Las siguientes líneas de salida representan la reanudación del procesamiento en startButton_Async
:
SIX: Back in startButton_Click.
Task getLengthTask is finished.
Result from AccessTheWebAsync is stored in contentLength.
About to display contentLength and exit.
La expresión await recupera del getLengthTask
valor entero que es el operando de la instrucción return en AccessTheWebAsync
. La siguiente instrucción asigna ese valor a la contentLength
variable .
Dim contentLength As Integer = Await getLengthTask
En la imagen siguiente se muestra el retorno del control de AccessTheWebAsync
a startButton_Click
.