jueves, 2 de junio de 2016

Receta Multithreading en C# No. 4-4: Cómo Convertir una Implementación en APM en una Tarea

Índice

1. Introducción
2. Palabras Clave
3. Problema
4. Solución
5. Discusión de la Solución
5.1 Asynchronous Programming Model (APM)
5.2 Task Parallel Library (TPL)
5.3 Método FromAsync
6. Práctica
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

Una implementación en APM (Asynchronous Programming Model) puede ser convertida al patrón TPL usando los artefactos de software que provee este enfoque basado en tareas. En esta receta se explora el proceso para comprender cómo llevar a cabo este tipo de conversión recurriendo a esta API introducida en versiones recientes de Microsoft .NET Framework. Se muestran tres enfoques distintos para lograr la conversión: uso de callback, sin uso de callback, y un tercer enfoque que consiste el uso de expresiones lambda para métodos asincrónicos no compatibles con las versiones sobrecargadas método FromAsync.

2. Palabras Clave

  • Asincronismo
  • APM
  • ATP
  • Callback
  • Expresión lambda
  • Tarea
  • TPL

3. Problema

Convertir una implementación en APM (Asynchronous Programming Model) al patrón TPL (Task Parallel Library).

4. Solución

El método sobrecargado FromAsync de la clase TaskFactory cuenta con diferentes versiones que permite al programador convertir una implementación en APM a TPL.

5. Discusión de la Solución

5.1 Asynchronous Programming Model (APM)

Nota: En la sección 3.3 de Receta Multithreading en C#: Invocación de un Delegado en un Pool de Threads se describe y demuestra el uso de este modelo para programación asincrónica.

5.2 Task Programming Model (TPM)

Nota: En la sección 3.4 de Receta Multithreading en C#: Invocación de un Delegado en un Pool de Threads se describe y demuestra el uso de este modelo para programación asincrónica.

5.2 Método FromAsync

FromAsync ("TaskFactory.FromAsync", 2016) permite la creación de una tarea a partir de una implementación bajo el patrón o modelo APM. Este método sobrecargado cuenta hasta 22 variantes.
Métodos sobrecargados de FromAsync
Figura 1. Métodos sobrecargados de FromAsync ("TaskFactory.FromAsync", 2016).
Para la sección práctica de esta receta se usarán tres de estos métodos para lograr implementar:
  • Conversión a tarea por medio del uso de un método callback
  • Conversión a tarea sin usar un método callback
  • Envoltura de un delegado incompatible con las versiones sobrecargadas de FromAsync.

6. Práctica

El siguiente ejemplo (adaptado de Agafonov (2013)) demuestra cómo llevar a cabo las diferentes formas de conversión de APM a TPL:

El método sobrecargado Prueba cuenta con las siguientes dos versiones:
  1. Prueba(string) (líneas 111-124): Esta implementación muestra indicador de inicio de ejecución (línea 113); luego indica si el thread de ejecución asociado está en el pool de threads(114). Simula el retardo en la ejecución con Thread.Sleep -2 segundos- (línea 118). El valor string pasado en el argumento se asigna como nombre del thread actual (línea 120). Este último valor formará parte de la cadena de caracteres retornada en la línea 123: el cual es el valor retornado por la ejecución del método asincrónico.
  2. Prueba(out int) (líneas 127-140): Realiza operaciones análogas a la primera versión; sin embargo el argumento es pasado con el modificador de parámetro out de tipo int, y su propósito es asociar el ID del thread.
Estos dos métodos serán referenciados por instancias de los delegados de las líneas 95 y 98.

Por otra parte, con el método Callback (líneas 101-108) se da respuesta a las llamadas asincrónicas del modelo APM. Este método será usado por dos de los enfoques de conversión utilizados en el método Main.

En Main (líneas 9-92) se llevan a cabo las siguientes operaciones:
  • Líneas 12-14: Creación de variables auxiliares para la contención del ID de un thread, delegado para el método Prueba (1) y otro delegado para el método Prueba (2).
  • Enfoque de conversión 1:
    • Líneas 19-22: Creación de tarea -tarea- para la invocación implícita (por medio del delegado ta). Se especifica el método de iniciación de la invocación de Prueba (junto con el parámetro -"ThreadTareaAsincronica"-) y el de finalización -Callback-.
    • Líneas 25-37: Con ContinueWith se da el siguiente paso en la ejecución de la tarea asincrónica y se muestra el mensaje resultando de su ejecución. Se muestra el estado de ejecución con el ciclo while.
  • Enfoque de conversión 2:
    • Líneas 45-47: Usa una versión sobrecargada alterna de FromAsync que no requiere el uso del método Callback (descrito arriba). Para la obtención de resultados se usa ContinueWith.
    • Líneas 49-62: Muestra mensajes similares a los descritos en las líneas 25-37.
  • Enfoque de conversión 3:
    • Debido a que no existe una versión FromAsync compatible con la firma del delegado TareaAsincronicaIncompatible, se opta por envolver el método de finalización -EndMethod- para ser invocado desde una expresión lambda (línea 72).
Compilación:

csc /t:exe ConversionAPMaTPL.cs

Ejecución assembly:

.\ConversionAPMaTPL.cs

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

> Prueba de ejecución (local): 
Ejecución assembly ConversionAPMaTPL.exe
Animación 1. Ejecución assembly ConversionAPMaTPL.exe.

7. Conclusiones

Se demostró a través de tres distintos enfoques cómo convertir una implementación asincrónica escrita bajo el modelo APM (Asynchronous Programming Model) al enfoque de tareas de TPL. El método FromAsync, como se mostró, posee varias versiones sobreescritas que se pueden acomodar a distintos requerimientos de implementación del modelo APM. De no existir una versión que se acomode a una al patrón o modelo APM se puede aún usar una solución como la presentada en la sección práctica -Enfoque de conversión 3-.

La próxima receta multithreading enseña cómo convertir desde el modelo EAP (Event-based Asynchronous Pattern) a TPL.

8. Literatura & Enlaces

Agafonov, E. (2013). Multithreading in C# 5.0 Cookbook. United States: Packt Publishing.
TaskFactory.FromAsync Method (System.Threading.Tasks) (2016, junio 2). Recuperado desde: https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.fromasync%28v=vs.110%29.aspx
Receta Multithreading en C# No. 3-1: Invocación de un Delegado en un Pool de Threads (2016, junio 2). Recuperado desde: http://ortizol.blogspot.com.co/2015/07/receta-multithreading-en-csharp-no-3-1-invocacion-de-un-delegado-en-un-pool-de-threads.html


V

No hay comentarios:

Publicar un comentario

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