viernes, 25 de marzo de 2016

Receta Multithreading en C# No. 4-2: Cómo Realizar Operaciones Asincrónicas Básicas con una Tarea

Índice

1. Introducción
2. Palabras Clave
3. Problema
4. Solución
5. Discusión de la Solución
5.1 Diferencia entre la ejecución de una tarea en un pool de threads y en el thread de Main
6. Práctica: Operaciones Asincrónicas y Sincrónicas con Task
7. Conclusiones
8. Literatura & Enlaces

1. Introducción

En la primera receta multithreading -de la serie librería Task Parallel Library-, se estudió las generalidades de la clase Task para la ejecución de operaciones asincrónicas. Ahora, en esta nueva receta se comprende con más detalle cómo realizar operaciones asincrónicas con una tarea; en particular, se muestra cómo obtener el valor de retorno de la ejecución de una tarea asincrónica con un objeto de tipo Task.

2. Palabras Clave

  • Asincronismo
  • Pool de threads
  • Sincronismo
  • Tarea
  • Thread

3. Problema

¿Cómo obtener el resultado de la ejecución de una operación asincrónica usando una tarea?

4. Solución

La clase Task cuenta con una propiedad para la obtención del resultado de la ejecución de una operación asincrónica: Task.Result.

5. Discusión de la Solución

5.1 Diferencia entre la ejecución de una tarea en un pool de threads y en el thread de Main

La invocación de métodos directamente desde el punto de entrada de la aplicación -Main-, se lleva a cabo de forma sincrónica: Main continua su ciclo de ejecución una vez que la invocación de cualquier método haya finalizado.

Por el contrario, la ejecución de métodos asincrónicos es posible gracias al mecanismo de paralelismo que provee la clase Task ("Task Class", 2016). Esta característica es la que permite la ejecución simultánea de varias tareas sobre una misma aplicación. (Esta propiedad potencializa la creación de aplicaciones software más robustas y eficientes en términos de uso de recursos del sistema.)

Sin embargo, es importante mencionar que la clase Task cuenta con el método RunAsynchronously ("TaskRunAsynchronously", 2016) para permitir la ejecución sincrónica de una tarea. El control de ejecución en este caso pasa al thread desde donde se invoca este último método; por ejemplo, a Main. Esta medida de ejecución evita, entonces, la ejecución asincrónica en un pool de threads ("Task Class", 2016).

Con la instrucción de la línea 11 se muestra mensaje del ID de thread sobre el que se está ejecutando el método Main.

Más adelante, en la líneas 14-29 se ejecuta modo asincrónico el cálculo de la suma de los números entre 1 y 1000000. De forma análoga, la tarea que se define en las líneas 31-46 realiza el mismo cómputo. Sin embargo, esta última se ejecutará de forma sincrónica con la invocación del método RunAsynchronously (línea 49). Al final de esta implimentación de ejemplo, se muestra los resultados de la suma en cuestión.

Compilación:

csc /t:exe PoolThreadsVsMainThread.cs

Ejecución assembly:

.\PoolThreadsVsMainThread.exe

Demostración ejecución assembly (ideone.com): http://ideone.com/V2HNtn


Demostración ejecución assembly (local):
Ejecución assembly PoolThreadsVsMainThread.exe
Figura 1. Ejecución assembly PoolThreadsVsMainThread.exe.

6. Práctica: Operaciones Asincrónicas y Sincrónicas con Task

En este ejemplo se demuestra (una vez más: esto con el propósito de afianzar el conocimiento teórico y práctico que pretende proporcionar esta receta) el uso de varios elementos de la clase Task para la ejecución de operaciones sincrónicas y asincrónicas.

En la línea 12 se invoca al método OperacionTask de forma sincrónica: directamente desde el método Main. En las líneas 15-18 ocurre lo siguiente:
  • Línea 15: creación nuevo objeto Task con el tipo paramétrico int.
  • Línea 16: inicio de la ejecución asincrónica del método OperacionTask.
  • Línea 17: obtención del resultado de la ejecución de OperacionTask.
  • Línea 18: visualización resultado obtenido.
De manera análoga, la ejecución sincrónica de OperacionTask realiza estas tareas anteriores; sin embargo, se usa la invocación de RunAsynchronously (línea 22) para hacer que el método en cuestión se ejecute de modo sincrónico. (Nota: el método OperacionTask no se ejecuta en el pool de threads.)

Luego, en la línea 27 se crea un nuevo objeto Task para ejecución asincrónica de OperacionTask. A este objeto se le computa su estado de completitud asincrónico con la propiedad IsCompleted (línea 32). Por cada ciclo del bloque while (líneas 32-36) se obtiene el estado actual de ejecución con la propiedad Status.

Finalmente, en las líneas 40-42, se computa:
  • el estado de ejecución del último objeto Task
  • el resultado obtenido de la ejecución de OperacionTask, y 
  • y la visualización del resultado anterior.
Compilación: 

csc /t:exe SincronismoAsincronismo.cs

Ejecución assembly:

.\SincronismoAsincronismo.exe

Demostración ejecución assembly (ideone.com): http://ideone.com/2a3Mxp

Demostración ejecución assembly (local): 
Ejecución assembly SincronismoAsincronismo.exe
Figura 2. Ejecución assembly SincronismoAsincronismo.exe.

7. Conclusiones

Se comprendió cómo es posible la ejecución de operaciones asincrónicas básicas usando la clase Task. Esta misma clase también provee el método RunAsynchronously para la ejecución de operaciones sincrónicas. En la sección práctica se demostró la diferencia entre ejecutar una operación asincrónica en el pool de threads y la ejecución de una operación sincrónica en el thread de Main.

En la siguiente receta multithreading se demuestra cómo combinar dos o más tareas.

8. Literatura & Enlaces

Agafonov, E. (2013). Multithreading in C# 5.0 Cookbook. United States: Packt Publishing.
Task Class (System.Threading.Tasks) (2016, marzo 25). Recuperado desde:
https://msdn.microsoft.com/en-us/library/system.threading.tasks.task(v=vs.110).aspx
Task.RunSynchronously Method (System.Threading.Tasks) (2016, marzo 25). Recuperado desde: https://msdn.microsoft.com/en-us/library/dd321435(v=vs.110).aspx


V

No hay comentarios:

Publicar un comentario

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