domingo, 23 de noviembre de 2014

WinForms Async: Evitando bloqueos en el ThreadUI

Con la llegada del Windows 8, Microsoft buscó una forma más sencilla para que los programadores utilicen hilos en paralelo al ThreadUI. La forma recomendada por Microsoft en el framework 4.5 es ejecutar un Task y utilizando el operador await para esperar de manera no bloqueante el fin de la ejecución. De esta manera nos libramos de gestionar Threads.

Internet está lleno de recursos para trabajar con Asyn y Await en WPF y Asp.Net pero para los veteranos del WinForms no hay tanta información, aunque el tratamiento es el mismo, os dejamos este video para ilustrar el proceso:

Resumiendo lo que dice el video. Cuando tienes procesos de larga duración como procesos pesados, llamadas a servicios web o sistemas lejanos, lo mejor es no hacerlos sobre el ThreadUI porque se bloquea y se detienen las animaciones, no puedes mover la ventana, etc. Lo mejor es hacerlo en paralelo. Antes eso se hacía con Hilos (en VB con DoEvents pero eso es otra historia), pero hay que tener cuidado al gestionarlos. En el framework 4.5 Microsoft añade el operador await

Se crea un Task con lo lo que se va a ejecutar y con el operador await se ejecuta la tarea en paralelo y se espera a que termine (en el video invoco al start de la tarea para dejar más claro la secuencia de ejcución, pero no es necesario). El ciclo de ejecución del una tarea se puede ver en esta imagen de la msdn:

AsyncAwait

El problema al usar otro hilo para hacer el trabajo es que no se puede actualizar el ThreadUI, en otras palabras, no tenemos acceso a los controles del la aplicación (formularios, cajas de texto, barras de progreso, botones, etc). Para ello podemos utilizar dos métodos de los controles: Invoke o BeginInvoke.

Invoke detiene el hilo donde se encuentra hasta que finaliza la ejecución el delegado que se le pasa por parámetro

ControlInvoke

Mientras que BeginInvoke no espera a que se termine la ejecución del delegado y sigue  ejecutando el hilo.

BeginInvoke

Las imagenes de Invoke y Begin Invoke son de Ryszard Dżegan para ilustrar esta respuesta en Stack Overflow.

1 comentario: