Visual Studio 2012
(algunos pensarán ya era hora jajajja). La intención es mirarme un poco el desarrollo de la nueva línea de diseño “metro” que me llama bastante. Ya os iré contando, inevitablemente algún artículo caerá jeje.Una de las novedades interesantes que incorpora Visual Studio 2012 respecto a
C#
y vb es la gestión de hilos asíncronos basado enTAP pattern
Task based Async pattern
. En este otro artículo ya exponíamos enareaTIC
las ventajas de la programación asíncrona respecto programación síncrona y por otro lado vimos que una de las desventajas es que la gestión del código se complica a medida que vamos implementando asíncronos. Con este nuevo patrón se pretende simplificar la gestión de código asíncrono respecto otros patrones como IAsyncPattern.A partir del framework 4.5 algunas clases del Framework ya incorporan métodos que implementan el patrón async y pueden usarse, como por ejemplo, System.Threading.Stream.CopyToAsync. El siguiente link de MSDN explica perfectamente cómo usar estos métodos usando el patrón TAP. En este ejemplo estamos usando un método del framework que ya está preparado para ser invocado vía TAP, a continuación veremos cómo convertir un método cualquiera para poder ser invocado vía TAP.
En principio si estamos trabajando con framework 4.5 y Visual Studio 2012 deberíamos poder añadir el modificador
async
a la firma de cualquiera de nuestros métodos, podemos hacer la prueba y tal vez recibiremos alguna advertencia pero compilará y podremos seguir usando el método una vez marcado con el modificadorasync
. Hasta aquí simplemente hemos marcado un método comoasync
pero no hemos hecho suficiente para garantizar que nuestro código sea asíncrono. Hacer que el código nuestro código sea asíncrono siguiendo este patrón no implica seguir siempre los mismos pasos si no que dependerá un poco del comportamiento que queramos aplicar en cada caso.Es importante entender el objeto
Task
, ya que se encarga de controlar el estado de la llamada asíncrona y proporcionar información sobre esta al hilo “padre”. Resumiendo y simplificando mucho, podemos invocar un método (que implementa TAP) y guardarnos un objeto Task, realizar ciertas acciones y posteriormente antes de salir del método “padre” recuperar el valor de respuesta de la primera llamada usando el comandoawait Task
. (en este artículo no profundizamos pero a partir de Task se puede tener acceso al progreso de la tarea, estado, excepciones, …)Para aplicar el patrón en un escenario diferente al típico de descargar contenido de una URL o escribir un fichero en disco, partimos de un ejemplo anterior de un artículo de
areaTIC
donde se explicaba como implementar IAsyncPattern. En el ejemplo simulamos tener 3 procesos que realizan trabajos de computación pesados y vimos como hacer 3 llamadas en 3 threads diferentes para evitar tener que esperar a que finalice un proceso para que el hilo de ejecución procese el siguiente… ConTAP
se puede llegar a hacer lo mismo, veamos un par de alternativas sobre el mismo caso de uso.En primer lugar tenemos que hacer que los métodos Proceso1, Proceso2, Proceso3 de la clase implementen el patrón TAP es decir que devuelvan un objeto Task
class Proceso
{
public Task ProcesoNegocio1(string pEntrada)
{
return Task.Run(() =>
{
//dormimos ejecución durante 7 segundos
//simulando una acción que tarda ese tiempo.
System.Threading.Thread.Sleep(7000);
//devolvemos fecha fin proceso concatenada a la fecha de entrada
return string.Format("Fin Proceso 1: {0}-{1}", pEntrada, DateTime.Now.ToString());
}, new CancellationToken());
}
public Task ProcesoNegocio2(string pEntrada)
{
return Task.Run(() =>
{
//dormimos ejecución durante 10 segundos
//simulando una acción que tarda ese tiempo.
System.Threading.Thread.Sleep(10000);
//devolvemos fecha fin proceso concatenada a la fecha de entrada
return string.Format("Fin Proceso 2: {0}-{1}", pEntrada, DateTime.Now.ToString());
}, new CancellationToken());
}
public Task ProcesoNegocio3(string pEntrada)
{
return Task.Run(() =>
{
//dormimos ejecución durante 3 segundos
//simulando una acción que tarda ese tiempo.
System.Threading.Thread.Sleep(3000);
//devolvemos fecha fin proceso concatenada a la fecha de entrada
return string.Format("Fin Proceso 3: {0}-{1}", pEntrada, DateTime.Now.ToString());
}, new CancellationToken());
}
}
Si os fijáis en estos métodos no hemos usado el modificador async en la firma, el modificador debería tenerlo el método “padre” que llamará a estos y realizará la gestión del multithreading. Veamos el método “padre” como quedaría:
async private void button1_Click(object sender, EventArgs e)
{
Proceso proceso = new Proceso();
Task result1 = proceso.ProcesoNegocio1(DateTime.Now.ToString());
Task result2 = proceso.ProcesoNegocio2(DateTime.Now.ToString());
Task result3 = proceso.ProcesoNegocio3(DateTime.Now.ToString());
Console.WriteLine(await result1);
Console.WriteLine(await result2);
Console.WriteLine(await result3);
}
A priori con esto ya haríamos que el hilo de ejecución principal procese en un thread diferente cada una de las 3 llamadas, de modo que estos realizarán el proceso y quedarán a la espera que solicitemos el resultado mediante el comando await
.Tal como hemos dejado el código obtendremos las respuestas por orden y mostraríamos el resultado, si os fijáis en el tiempo de entrada y fin de cada proceso que escribimos en consola veréis que la gestión ha sido asíncrona y que no necesariamente el orden de finalización de cada método coincide con el orden en que solicitamos la respuesta usando await. Podríamos haber llegado a usar IEnumarable
Hasta aquí el artículo de hoy se agradecen vuestros comentarios, debates, valoraciones, etc… que sino esto es muy aburrido jajaja. Como siempre recordaros que podéis seguir

