Exportar (0) Imprimir
Expandir todo
Este artículo se tradujo de forma manual. Mueva el puntero sobre las frases del artículo para ver el texto original. Más información.
Traducción
Original

Programación asincrónica con Async y Await (C# y Visual Basic)

Puede evitar cuellos de botella de rendimiento y mejorar la capacidad de respuesta global de la aplicación mediante la programación asincrónica. Sin embargo, las técnicas tradicionales para escribir aplicaciones asíncronas pueden resultar complicadas, haciéndolas difíciles de escribir, depurar, y mantener.

Visual Studio 2012 presenta un enfoque simplificado, programación asincrónica, que aprovecha la compatibilidad asincrónica en .NET Framework 4.5 y Windows en tiempo de ejecución. El compilador realiza el trabajo difícil que el desarrollador solía hacer, y la aplicación conserva una estructura lógica similar al código síncrono. Como resultado, se obtienen todas las ventajas de la programación asincrónica con una parte del trabajo.

Este tema contiene las secciones siguientes.

Este tema proporciona información general sobre cuándo y cómo utilizar la programación asincrónica e incluye vínculos que admiten temas con detalles y ejemplos.

La asincronía es esencial para las actividades que son potencialmente bloqueantes, por ejemplo cuando su aplicación accede a la web. El acceso a un recurso web a veces es lento o con retrasos. Si tal actividad queda bloqueada dentro de un proceso sincrónico, toda la aplicación deberá esperar. En un proceso asíncrono, la aplicación puede continuar con otro trabajo que no depende del recurso web hasta que la tarea potencialmente bloqueante finaliza.

La tabla siguiente muestra las áreas típicas donde la programación asíncrona mejora su capacidad de respuesta. Las API mencionadas de .NET Framework 4.5 y Windows Runtime contienen métodos que soportan la programación async.

Área de aplicación

Compatibilidad de las API que contienen métodos asincrónicos

Acceso web

HttpClient , SyndicationClient

Trabajar con archivos

StorageFile, StreamWriter, StreamReader, XmlReader

Trabajar con imágenes

MediaCapture, BitmapEncoder, BitmapDecoder

Programar WCF

Operaciones sincrónicas y asincrónicas

La asincronía resulta especialmente valiosa para aplicaciones que tienen acceso al subproceso de la interfaz de usuario porque toda la actividad relacionada con la interfaz de usuario por lo general comparte un hilo. Si cualquier proceso es bloqueado en una aplicación sincrónica, todos los los demás también serán bloqueados. La aplicación deja de responder, y usted puede pensar que ha fallado, cuando en realidad sólo está esperando.

Cuando utiliza métodos asíncronos, la aplicación continúa respondiendo a la interfaz de usuario. Puede cambiar el tamaño o minimizar una ventana, por ejemplo, o puede cerrar la aplicación si no desea esperar a que finalice.

El enfoque basado en async agrega el equivalente de una transmisión automática a la lista de opciones entre las que puede elegir al diseñar operaciones asíncronas. Es decir, obtiene todas las ventajas de la programación asincrónica tradicional pero con mucho menos esfuerzo del desarrollador.

Las palabras clave de Async y de Espera (Await) en Visual Basic y las palabras clave de async y de espera (await) en C# son el núcleo de programación asíncrona. Con esas dos palabras clave, se pueden utilizar los recursos en .NET Framework o en Windows en tiempo de ejecución para crear un método asincrónico casi tan fácilmente como se crea un método sincrónico. Los métodos asíncronos que se define utilizando async y await se denominan métodos async.

En el ejemplo siguiente se muestra un método asincrónico. Casi todo el código deberá ser totalmente familiar. Los comentarios informan sobre las características que se agregan para crear el asincronismo.

Puede encontrar el archivo de ejemplo completo al final de este tema y puede descargar el ejemplo Async: ejemplo de "programación asincrónica con Async y Await" .


// Three things to note in the signature:
//  - The method has an async modifier. 
//  - The return type is Task or Task<T>. (See "Return Types" section.)
//    Here, it is Task<int> because the return statement returns an integer.
//  - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync.
    //  - AccessTheWebAsync can't continue until getStringTask is complete.
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync.
    //  - Control resumes here when getStringTask is complete. 
    //  - The await operator then retrieves the string result from getStringTask.
    string urlContents = await getStringTask;

    // The return statement specifies an integer result.
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
    return urlContents.Length;
}


Si AccessTheWebAsync no tiene ningún trabajo que se pueda hacer entre llamar a GetStringAsync y esperar a su finalización, se puede simplificar el código llamando y esperando en la siguiente instrucción única.

string urlContents = await client.GetStringAsync();

Las siguientes características resumen lo que hace que el ejemplo anterior sea un método asincrónico.

  • La signatura del método incluye un modificador Async o async.

  • El nombre de un método asincrónico, por convención, finaliza con un sufijo “Async”.

  • El tipo de valor devuelto es uno de los tipos siguientes:

    • Task<TResult> si el método tiene una instrucción return en la que el operando tiene el tipo TResult.

    • Task si el método no tiene ninguna instrucción return o tiene una instrucción return sin operando.

    • Void (Sub en Visual Basic) si está escribiendo un controlador de eventos asincrónicos.

    Para obtener más información, vea "Tipos de valor devuelto y parámetros" más adelante en este tema.

  • El método normalmente incluye al menos una expresión await, que marca un punto en el que el método no puede continuar hasta que se completa la operación asíncrona en espera. Mientras tanto, se suspende el método y el control vuelve al llamador del método. La sección siguiente de este tema muestra lo que sucede en el punto de suspensión.

En métodos asíncronos, se utilizan las palabras clave y los tipos proporcionados para indicar lo que desea hacer, y el compilador realiza el resto, incluido el seguimiento de qué debe ocurrir cuando el control vuelve a un punto de aguardar en un método suspendido. Algunos procesos de rutina, tales como bucles y control de excepciones, pueden ser difíciles de controlar en código asincrónico tradicional. En un método asincrónico, se pueden escribir estos elementos como se haría en una solución sincrónica y se resuelve este problema.

Para obtener más información sobre la asincronía en las versiones anteriores de .NET Framework, vea TPL y la programación asincrónica tradicional de .NET Framework.

Lo más importante de entender en la programación asincrónica es cómo el flujo de control pasa de un método a otro. El diagrama siguiente le guía por el proceso.

Seguimiento de un programa asincrónico

Los números en el diagrama se corresponden con los pasos siguientes.

  1. Un controlador de eventos llama a y espera el método asincrónico AccessTheWebAsync.

  2. AccessTheWebAsync crea una instancia HttpClient y llama al método asincrónico GetStringAsync para descargar el contenido de un sitio web como una cadena.

  3. Sucede algo en GetStringAsync que suspende el progreso. Quizás debe esperar a un sitio web para realizar la descarga o alguna otra actividad de bloqueo. Para evitar bloqueos de recursos, GetStringAsync cede el control al llamador, AccessTheWebAsync.

    GetStringAsync devuelve un Task<TResult> donde TResult es una cadena, y AccessTheWebAsync asigna la tarea a la variable getStringTask. La tarea representa el proceso actual para la llamada a GetStringAsync, con el compromiso de generar un valor de cadena real cuando se completa el trabajo.

  4. Debido a que getStringTask no se ha esperado, AccessTheWebAsync puede continuar con otro trabajo que no dependa del resultado final de GetStringAsync. Ese trabajo se representa mediante una llamada al método sincrónico DoIndependentWork.

  5. DoIndependentWork es un método sincrónico que funciona y vuelve al llamador.

  6. AccessTheWebAsync se ha quedado sin el trabajo que puede realizar sin un resultado de getStringTask. AccessTheWebAsync desea calcular y devolver la longitud de la cadena descargada, pero el método no puede calcular ese valor hasta que el método tenga la cadena.

    Por consiguiente, AccessTheWebAsync utiliza un operador de aguardar para suspender el progreso y ceder el control al método que llamó a AccessTheWebAsync. La llamada a AccessTheWebAsync devuelve Task(Of Integer) o Task<int> al llamador. La tarea representa una sugerencia para generar un resultado entero que es la longitud de la cadena descargada.

    Nota Nota

    Si se completa GetStringAsync (y por consiguiente getStringTask) antes de que AccessTheWebAsync lo espere, permanece el control en AccessTheWebAsync. El gasto de suspensión y después regresar a AccessTheWebAsync se desperdiciaría si el proceso denominado asincrónico (getStringTask) ya se ha completado y AccessTheWebSync no tiene que esperar el resultado final.

    Dentro del llamador (el controlador de eventos en este ejemplo), el patrón de procesamiento continúa. El llamador puede hacer otro trabajo que no depende del resultado de AccessTheWebAsync antes de esperar ese resultado, o es posible que el llamador se espere inmediatamente. El controlador de eventos está esperando AccessTheWebAsync, y AccessTheWebAsync está esperando GetStringAsync.

  7. GetStringAsync completa y genera un resultado de la cadena. La llamada a GetStringAsync no devuelve el resultado de la cadena de la manera que cabría esperar. (Recuerde que el método ya devolvió una tarea en el paso 3.) En su lugar, el resultado de cadena se almacena en la tarea que representa la finalización del método, getStringTask. El operador await recupera el resultado de getStringTask. La instrucción de asignación asigna el resultado recuperado a urlContents.

  8. Cuando AccessTheWebAsync tiene el resultado de la cadena, el método puede calcular la longitud de la cadena. El trabajo de AccessTheWebAsync también se completa y el controlador de eventos que espera se puede reanudar. En el ejemplo completo del final de este tema, puede comprobar que el controlador de eventos recupera e imprime el valor de resultado de longitud.

Si no está familiarizado con la programación asincrónica, reserve un minuto para ver la diferencia entre el comportamiento sincrónico y asincrónico. Un método sincrónico devuelve cuando se completa su trabajo (paso 5), pero un método asincrónico devuelve un valor de tarea cuando se suspende el trabajo (pasos 3 y 6). Cuando el método asincrónico completa finalmente el trabajo, se marca la tarea como completa y el resultado, si existe, se almacena en la tarea.

Para obtener más información acerca del flujo de control, vea Flujo de control en programas asincrónicos (C# y Visual Basic).

Tal vez se pregunte dónde encontrar métodos como GetStringAsync que soporten programación async. La versión .NET Framework 4.5 contiene muchos miembros que trabajan con async y await. Puede reconocer estos miembros por el sufijo "Async" que está adjunto al nombre del miembro y por un tipo de valor devuelto Task o Task<TResult>. Por ejemplo, la clase System.IO.Stream contiene métodos como CopyToAsync, ReadAsync y WriteAsync junto con los métodos sincrónicos CopyTo, Read y Write.

Windows en tiempo de ejecución también contiene muchos métodos que puede utilizar con async y await en aplicaciones de Tienda Windows. Para obtener más métodos de ejemplo e información, vea Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic, Programación asincrónica (aplicaciones de la Tienda Windows) y WhenAny: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic).

La intención de los métodos Async es ser aplicaciones que no pueden producir bloqueos. Una expresión await en un método asincrónico que no bloquea el subproceso actual mientras la tarea esperada se está ejecutando. En vez de ello, la expresión declara el resto del método como una continuación y devuelve el control al llamador del método asincrónico.

Las palabras clave async y await no hacen que se creen subprocesos adicionales. Los métodos Async no requieren multithreading, ya que un método asincrónico no se ejecuta en su propio subproceso. El método se ejecuta en el contexto de sincronización actual y ocupa tiempo en el subproceso únicamente cuando el método está activo. Puede utilizar Task.Run para mover el trabajo ligado a la CPU a un subproceso de fondo, pero un subproceso de fondo no ayuda a un proceso que simplemente está esperando resultados para estar disponible.

El enfoque de la programación asíncrona basada en async es preferible a los enfoques existentes en casi todos los casos. En concreto, este enfoque es mejor que BackgroundWorker para las operaciones ligadas a IO porque el código es más fácil y no se tiene que proteger contra las condiciones de carrera. Junto con Task.Run, la programación asincrónica es mejor que BackgroundWorker para las operaciones enlazadas a la CPU porque la programación asincrónica separa los detalles de coordinación en la ejecución del código del trabajo que Task.Run transfiere al grupo de subprocesos.

Si especifica que un método es un método asincrónico utilizando un modificador Async o async, habilita las dos funciones siguientes.

  • El método marcado async puede utilizar Espera o espera para notificar los puntos de suspensión. El operador await indica al compilador que el método async no pueda continuar a partir de ese punto hasta que se complete el proceso asíncrono esperado. Mientras tanto, el control devuelve al llamador del método asincrónico.

    La suspensión de un método asincrónico en una expresión await no constituye a una salida del método y los bloques finally no se ejecutan.

  • El método async marcado se puede aguardar a sí mismo por metodos que lo llaman.

Un método async normalmente contiene una o más apariciones de un operador de aguardar, pero la ausencia de expresiones de espera no produce un error del compilador. Si un método asincrónico no usa un operador await para marcar el punto de suspensión, se ejecuta como un método sincrónico, a pesar del modificador async. El compilador detecta una advertencia para dichos métodos.

Async , async, Await y await son palabras clave contextuales. Para mayor información y ejemplos, vea los siguientes temas:

En la programación de .NET Framework, un método asincrónico devuelve normalmente Task o Task<TResult>. Dentro de un método asincrónico, se aplican a un operador await a una tarea que devuelve una llamada a otro método asincrónico.

Puede especificar Task<TResult> como tipo de valor devuelto si el método contiene una instrucción Return (Visual Basic) o return (C#) que especifica un operando de tipo TResult.

Utiliza Task como tipo de valor devuelto si el método no tiene ninguna instrucción return o tiene una instrucción return que no devuelve un operando.

El ejemplo siguiente muestra cómo declarar y llamar a un método que devuelve Task<TResult> o Task.

// Signature specifies Task<TResult>
async Task<int> TaskOfTResult_MethodAsync()
{
    int hours;
    // . . .
    // Return statement specifies an integer result.
    return hours;
}

// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();


// Signature specifies Task
async Task Task_MethodAsync()
{
    // . . .
    // The method has no return statement.  
}

// Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync();
await returnedTask;
// or, in a single statement
await Task_MethodAsync();

Cada tarea devuelta representa el trabajo en curso. Una tarea encapsula la información sobre el estado del proceso asincrónico y, finalmente, el resultado final del proceso o la excepción que el proceso provoca si no tiene éxito.

Un método asincrónico también puede ser un método Sub (Visual Basic) o tener un tipo de valor devuelto void (C#). Este tipo de valor devuelto se utiliza principalmente para definir controladores de eventos, donde se requiere un tipo de valor devuelto void. Los controladores de eventos asincrónicos sirven a menudo como punto de partida para programas asincrónicos.

No se puede esperar a un método asincrónico que sea un procedimiento Sub o que tenga un tipo de retorno void y el llamador de un método con tipo de retorno void no puede capturar ninguna excepción producida por este.

Un método asincrónico no puede declarar parámetros ByRef en Visual Basic o parámetros ref u out en C#, pero el método puede llamar a otros métodos que tengan dichos parámetros.

Para obtener más información y ejemplos, vea Tipos de valor devuelto de Async (C y Visual Basic). Para obtener más información sobre cómo detectar excepciones en métodos asincrónicos, vea try-catch (Referencia de C#) o Instrucción Try...Catch...Finally (Visual Basic).

Las API asincrónicas en la programación Windows en tiempo de ejecución tienen uno de los siguientes tipos de valor devuelto, que son similares a las tareas:

Para obtener más información y un ejemplo, vea Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic.

Por convención, se anexa "Async" a los nombres de métodos que tengan modificadores Async o async.

Puede ignorar esta convención cuando un evento, clase base o contrato de interfaz sugieren un nombre diferente. Por ejemplo, no se debería cambiar el nombre de los controladores de eventos, tales como Button1_Click.

Título

Descripción

Ejemplo

Walkthrough: Acceso a web usando Async y Await (C# y Visual Basic)

Muestra cómo convertir una solución WPF sincrónica en una solución WPF asincrónica. La aplicación descarga una serie de sitios web.

Ejemplo Async: obtener acceso al tutorial web (C# y Visual Basic)

Cómo: Ampliar el tutorial de Async usando Task.WhenAll (C# y Visual Basic)

Agrega Task.WhenAll al tutorial anterior. El uso de WhenAll inicia todas las descargas al mismo tiempo.

Cómo: Hacer varias solicitudes web en paralelo utilizando Async y Await (C# y Visual Basic)

Demuestra cómo comenzar varias tareas al mismo tiempo.

Ejemplo Async: hacer varias solicitudes web en paralelo (C# y Visual Basic)

Tipos de valor devuelto de Async (C y Visual Basic)

Muestra los tipos que los métodos asincrónicos pueden devolver y explica cuándo es apropiado cada uno de ellos.

Flujo de control en programas asincrónicos (C# y Visual Basic)

Rastrea en detalle el flujo de control a través de una sucesión de expresiones await en un programa asincrónico.

Ejemplo Async: flujo de control en programas Async (C# y Visual Basic)

Ajustar una aplicación asincrónica (C# y Visual Basic)

Muestra cómo agregar la siguiente funcionalidad a la solución asincrónica:

Ejemplo Async: ajuste de la aplicación (C# y Visual Basic)

Controlar cómo se vuelve a entrar en aplicaciones asincrónicas (C# y Visual Basic)

Muestra cómo controlar los casos en los que se reinicia una operación asincrónica activa mientras se ejecuta.

WhenAny: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic)

Muestra cómo unir entre tipos de tareas en .NET Framework e IAsyncOperations en Windows en tiempo de ejecución para poder utilizar WhenAny con un método Windows en tiempo de ejecución.

Ejemplo Async: puente entre .NET y Windows en tiempo de ejecución (AsTask y WhenAny)

Cancelación asincrónica: Puente entre .NET Framework y Windows en tiempo de ejecución (C# y Visual Basic)

Muestra cómo unir entre tipos de tareas en .NET Framework e IAsyncOperations en Windows en tiempo de ejecución para poder utilizar CancellationTokenSource con un método Windows en tiempo de ejecución.

Ejemplo Async: puente entre .NET y Windows en tiempo de ejecución (AsTask & Cancellation)

Usar Async en acceso a archivos (C# y Visual Basic)

Enumera y demuestra los beneficios de usar async y await para obtener acceso a archivos.

Tutorial: Usar el depurador con métodos asincrónicos

Muestra el flujo de control en una instrucción await y muestra el comportamiento de los comandos Paso a paso por instrucciones, Paso a paso por procedimientos y Paso a paso para salir en métodos asincrónicos.

Modelo asincrónico basado en tareas (TAP)

Describe un nuevo patrón de asincronía en .NET Framework. El patrón está basado en los tipos Task y Task<TResult>.

Inicio rápido: llamadas a API asincrónicas en C# o Visual Basic

Muestra como usar async y await en una aplicación Tienda Windows.

Programación asincrónica (aplicaciones de la Tienda Windows)

Proporciona información general sobre la programación asincrónica en Windows en tiempo de ejecución.

Vídeos de Channel 9

Proporciona vínculos a una serie de vídeos sobre programación asincrónica.

El código siguiente es el archivo MainWindow.xaml.vb o MainWindow.xaml.cs de la aplicación de Windows Presentation Foundation (WPF) que se explica en este tema. Puede descargar el ejemplo de Ejemplo de Async: ejemplo de "programación asincrónica con Async y Await".


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 AsyncFirstExample
{
    public partial class MainWindow : Window
    {
        // Mark the event handler with async so you can use await in it.
        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // Call and await separately.
            //Task<int> getLengthTask = AccessTheWebAsync();
            //// You can do independent work here.
            //int contentLength = await getLengthTask;

            int contentLength = await AccessTheWebAsync();

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


        // Three things to note in the signature:
        //  - The method has an async modifier. 
        //  - The return type is Task or Task<T>. (See "Return Types" section.)
        //    Here, it is Task<int> because the return statement returns an integer.
        //  - The method name ends in "Async."
        async Task<int> AccessTheWebAsync()
        { 
            // You need to add a reference to System.Net.Http to declare client.
            HttpClient client = new HttpClient();

            // GetStringAsync returns a Task<string>. That means that when you await the
            // task you'll get a string (urlContents).
            Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

            // You can do work here that doesn't rely on the string from GetStringAsync.
            DoIndependentWork();

            // The await operator suspends AccessTheWebAsync.
            //  - AccessTheWebAsync can't continue until getStringTask is complete.
            //  - Meanwhile, control returns to the caller of AccessTheWebAsync.
            //  - Control resumes here when getStringTask is complete. 
            //  - The await operator then retrieves the string result from getStringTask.
            string urlContents = await getStringTask;

            // The return statement specifies an integer result.
            // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
            return urlContents.Length;
        }


        void DoIndependentWork()
        {
            resultsTextBox.Text += "Working . . . . . . .\r\n";
        }
    }
}

// Sample Output:

// Working . . . . . . .

// Length of the downloaded string: 41564.


Adiciones de comunidad

AGREGAR
Mostrar:
© 2014 Microsoft