jueves, 8 de noviembre de 2012

Programacion asincrona con async y await

A veces no sabemo cómo lidiar con la latencia de una operación remota, se nos enrreda el código cuando no queremos esperar por la terminación de la invocación a un método del que se puede incluso no retornar. En este artículo echaremos un vistazo al nuevo recurso lingüístico async/await, que tenemos a nuestra disposicion en C# y VB a travez de Microsoft Visual Studio Async CTP, así como al patrón propuesto para utilizar dicho recurso, que nos simplifica la forma de hacer programación asíncrona.

Descargar de Microsoft Visual Studio Async CTP

Entrando en materia:

Para ilustrar el ejemplo usaremos el famoso algoritmo MergeSort (ordenacion por mezcla) en un projecto de consola

private static void Merge(int[] A, int p, int q, int r, int[] interchange)
{
 
// ...
}
public static void MergeSort(int[] A, int p, int r, int[] interchange)
{
 
if (p < r)
 
{
   
var q = (int)Math.Floor((p + r) / 2.0);
   
MergeSort(A, p, q, interchange);
   
MergeSort(A, q + 1, r, interchange);
   
Merge(A, p, q, r, interchange);
   
Array.Copy(interchange, p, A, p, r - p + 1);
 
}
}
static void Main(string[] args)
{
 
Stopwatch crono = new Stopwatch();
 
Console.Write("Entrar tamaño del array ");
 
string s = Console.ReadLine();
 
int n = int.Parse(s);      
 
int[] a = CreaRandomArray(n);
 
Console.WriteLine("\nOrdenando");
 crono
.Restart();
 
Sort.MergeSort(a, 0, a.Length - 1, new int[a.Length]);
 
Console.WriteLine("Tiempo MergeSort síncrono {0} ms", crono.ElapsedMilliseconds);
}




Esto provocara que nuestra ventana de consola se congele, hasta que no termine de prosesar no podremos usarla.


Ventana conjelada esperando por la ordenacion.



Codigo: usando hebras explisitamente para lograr asincronia:
static void Pointing()
{
 
Thread.Sleep(200);
 
Console.Write(".");
}

 
// ...
 
Console.WriteLine("\nOrdenando asíncronamente usando hebras");
 crono
.Restart();
 
Thread h = new Thread(() => {Sort.MergeSort(a, 0, a.Length - 1, new int[a.Length]);});
 h
.Start();
 
while (h.ThreadState == System.Threading.ThreadState.Running)
   
Pointing();
 
Console.WriteLine("\nTiempo MergeSort asíncrono {0} ms", crono.ElapsedMilliseconds);



Ventana mientras se esta ordenando.





El nuevo enfoque con Async

Con los nuevos recursos propuestos en Microsoft Visual Studio Async CTP, el código para calcular la mediana ( aquel valor que tiene en el array igual cantidad de valores mayores que él que de menores que él) de un arreglo ya ordenado con MergeSort, se escribiría de forma más simple como se muestra


public static async Task<int> MedianaAsync(int[] a)
{
 await
TaskEx.Run(() => { MergeSort(a, 0, a.Length - 1, new int[a.Length]); });
 
return a[a.Length / 2];
}

 
// ...
 crono
.Restart();
 
var t = Sort.MedianaAsync(a);
 
while (!t.IsCompleted) Pointing();
 
Console.WriteLine("\nLa mediana es {0} calculada en {1} ms",
                   t
.Result, crono.ElapsedMilliseconds);


Otras Referencias:
http://msdn.microsoft.com/en-us/library/hh191443(v=vs.110).aspx
http://www.slideshare.net/eduardtomas/async-await-12horas 
http://www.dnmplus.net/articulos/programacion-asincrona-en-csharp-50.aspx