domingo, 26 de junio de 2016

Receta Multithreading en C# No. 5-1: Obtención de Resultados de Tareas Asincrónicas con el Operador await

Índice

1. Introducción
2. Palabras Clave
3. Problema
4. Solución
5. Discusión de la Solución
5.1 Operador await
6. Práctica: Invocación Asincrónica con Operador Await y TPL
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

A partir de esta receta multithreading se da inicio a una nueva serie llamada Uso de C# 5.0, la cual está enfocada en explorar y poner en práctica varios de los nuevos conceptos de asincronismo sobre esta versión del lenguaje de programación. Entre las capacidades sobresalientes se hayan la de proveer al programador de mecanismos de control para determinar el flujo de ejecución de operaciones asincrónicas, gestión del contexto de ejecución para acceso al estado de controles de interfaz gráfica de usuario, manejo del encadenamiento de continuaciones de tareas, entre otras características más. Estas capacidades están implementadas como funciones asincrónicas para permitir la programación de aplicaciones asincrónicas de forma más simple. Entre las construcciones nuevas que forman parte de estas funciones asincrónicas se haya async y await:

async Task<string> ObtenerVersionCSharpAsync()
{
await Task.Delay(TimeSpan.FromSeconds(3));
return "C# 5.0";
}


Este elemento de programa -async- convierte a una función en asincrónica, además que permite la especificación de un tipo de dato de retorno en un objeto de tipo Task. En igual profundidad el operador asincrónico await, será detalladamente estudiado: esta función asincrónica espera a la ejecución de una tarea hasta obtener un resultado de interés.


Estas capacidades mantendrán un flujo de control lineal aún con capacidades asincrónicas; como será demostrado en las recetas multithreading subsiguientes.


Por otra parte, también se discutirá algunas de las limitaciones o restricciones del uso de async y await; por ejemplo, el método Main no puede ser marcado con async, o usar el operador en bloques como catch, finally, lock o unsafe. Tampoco está permitido el uso de parámetros ref y out en una función asincrónica. Estas restricciones como otras serán tratadas a lo largo de esta sorprendente serie.


Para empezar, en esta primera receta multithreading, el programador aprenderá a usar el operador await para la obtención de resultados de tareas asincrónicas. Se hará énfasis en el contraste: obtención de resultado asincrónico con las construcciones de Task Parallel Library y el operador asincrónico await.


¡Manos a la obra!

2. Palabras Clave

  • Asincronismo
  • await
  • Flujo de control de programa
  • Función asincrónica
  • Multithreading
  • Sincronismo
  • TPL

3. Problema

Obtener el resultado de una tarea asincrónica.

4. Solución

El nuevo operador await permite obtener el resultado de una tarea u operación asincrónica.

5. Discusión de la Solución

5.1 Operador await

Con el operador await se especifica a una tarea asincrónica la espera de la terminación de la ejecución de un método. Hasta que la ejecución de este método no se complete, el control de ejecución no pasa de nuevo a la función que le invocó ("await (C# Reference)", 2016).

Es importante saber que el método donde este operador se aplique debe estar marcado con el operador asincrónico async. Por ejemplo: 

async Task<string> ObtenerVersionCSharp()
{
await Task.Delay(TimeSpan.FromSeconds(3));
return "C# 5.0";
}

Con await Task.Delay(TimeSpan.FromSeconds(3)); se está expresando que se ha de esperar la ejecución de Task.Delay(TimeSpan.FromSeconds(3)) -retraso de 3 segundos en la ejecución-; luego retornará la cadena "C# 5.0", el cual corresponde con el tipo paramétrico del tipo de dato retorno: Task<string>.

Otro ejemplo podría ser: 

private async Task ObtenerContenidoPaginaAsync()
{
// Creación de cliente para peticiones HTTP:
HttpClient cliente = new HttpClient();

// Otras operaciones...

// Lectura del contenido desde el URL especificiado:
Task<byte[]> contenido = client.GetByteArrayAsync(url);

// Obtención del contenido:
byte[] contenidoPagina = await getContentsTask;

// Alternativa sintáctica: byte[] contenidoPagina = await cliente.GetByteArrayAsync(url);
// Otras operaciones...
}

6. Práctica: Invocación Asincrónica con Operador await y TPL

La aplicación consola creada para este ejemplo demuestra cómo usar el operador await y elementos de programa de TPL para ejecutar una operación asincrónica.

El método ObtenerInfoAsincronico() (líneas 65-74) efectúa las siguientes operaciones: 
  • Línea 67: Invocación de Task.Dalay() con la función asincrónica await. Se pasa como argumento TimeSpan.FromSeconds(2) para simular una operación extendida.
  • Líneas 69-73: Retorna cadena de texto con la información del thread donde se ejecuta la operación asincrónica.
Con los métodos AsincronismoConTpl() y AsincronismoConAwait() se contrasta la invocación con los elementos de programa estándar de TPL y a través del uso del operador await.

Para el método AsincronismoConTpl() (líneas 31-41) se tiene esta implementación: 
  • Línea 33: Declaración de objeto Task con tipo paramétrico string. Se asigna el resultado de la invocación del método ObtenerInfoAsincronico().
  • Líneas 35-38: Definición de continuaciones en caso de generarse o no una excepción.
  • Línea 40: Retorna cualquiera de las continuaciones definidas que termine primero.
En cuanto al método AsincronismoConAwait() (líneas 47-58) se tiene: 
  • Líneas 49-53: Bloque try para la invocación de ObtenerInfoAsincronico() por medio del operador await.
  • Línea 52: Visualización del resultado en la salida estándar.
  • Líneas 54-57: Bloque catch para responder a una posible excepción que pudiera generarse en la invocación asincrónica.
El siguiente vídeo demuestra a través de una aplicación basada en consola la ejecución de estos métodos:
En este enlace de GitHub puede encontrar la solución de Visual Studio 2015 y los proyectos asociados a esta receta y otras más: https://github.com/Fhernd/RecetasMultithreadingCSharp

> Prueba de ejecución(online): http://ideone.com/BRZRYy

7. Conclusiones

Se ha demostrado el uso de la función asincrónica await para ejecutar una operación asincrónica. Quedó claro, además, la diferencia entre ejecutar una operación asincrónica con los elementos de programa de TPL y con este nuevo operador de asincronismo de C# 5.0.

La próxima receta multithreading demuestra cómo usar el operador await en una expresión lambda.

8. Literatura & Enlaces

Agafonov, E. (2013). Multithreading in C# 5.0 Cookbook. United States: Packt Publishing.
await (C# Reference) (2016, junio 26). Recuperado desde: https://msdn.microsoft.com/en-us/library/hh156528.aspx?f=255&MSPPError=-2147217396


V

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.