vtortola.Net

Abril 24, 2007

Modelo Asíncrono. Parte I, invocación.

Archivado en: .NET, C#, Modelo Asíncrono — vtortola @ 10:56 am

Una de las cosas que definitivamente más me gustan de programar en .NET es el modelo asíncrono de desarrollo. No solo es una técnica para poder ejecutar tareas en segundo plano, es todo un planteamiento a la hora de diseñar el comportamiento de nuestras aplicaciones. Da más escalabilidad que el modelo multithreading tradicional y sobre todo deja un código más claro (a mi gusto claro :P ). Atrás quedan aquellas largas líneas con ParameterizedThreadStart, los objetos Thread, los eventos para devolver resultados y otras perlas que hacian un poco tediosa la programación multihilo tan necesaria cuando trabajamos con máquinas SMP ó/y cuando hacemos uso de recursos con una latencia considerable.

Como no puedo ni extender ni completar más la excelente documentación sobre el tema que existe en MSDN, escribiré una serie de artículos con pequeños ejemplos explicados, que muestren la sencillez del proceso y los truquillos que he ido aprendiendo con el tiempo. Colgaré aquí también los proyectos comprimidos en .Zip para quien lo quiera descargar. Si necesitais una explicación más profunda sobre el tema teneis un excelente artículo en MSDN titulado Llamar a métodos sincrónicos de forma asincrónica.

En este primer ejemplo, mostraré lo básico, como llamar a una función de forma asíncrona y obtener un resultado de salida.

// Declaro el delegado
// con parámetro de salida.

private delegate void AsyncCallOut_(string p1, int p2, out StringBuilder parametroSalida);
private static AsyncCallOut_ AsynCallOut;

/// <summary>
/// Punto de entrada de la aplicación.
/// </summary>
/// <param name=”args”>Argumentos pasados como parámetros al ejecutable.</param>
static void Main(string[] args)
{

// Asigno los delegados apuntando a la función que ejecutará de forma asíncrona
// La firma del método debe coincidir con la firma del delegado.
AsynCallOut = new AsyncCallOut_(AsyncFuncOut);

// Invoco 5 operaciones asíncronas para el primer ejemplo.
StringBuilder sb;
for(int i=0;i<5;i++)
{

// La sintáxis de .BeginInvoke es:
// 1º : Parámetros de la firma del delegado.
// Son accesibles desde la función que ejecutaremos de forma asíncrona,
// Tanto los de entrada como los de entrada/salida.

// 2º : AsynCallBack a función con firma (IAsyncResult ia) que se ejecutará
// al finalizar el método asíncrono.

// 3º : ObjectState, objeto que será devuelto a la finalización
// del método. No es accesible desde la función que ejecutaremos
// de forma asíncrona.

// ‘out’ nos permite pasar como parámetro una variable sin inicializar y
// obligará en el método en cuestión a ser inicializada antes de abandonarlo.
// Para estos menesteres es más apropiado que usar ‘ref’, ya que lo que nos
// interesa es que dentro del método se le dé valor, mientras que ‘ref’ nos
// obligaria a darle valor antes de usarla para llamar a .BeginInvoke.

AsynCallOut.BeginInvoke(string.Format(“Prueba 1.{0}”, i), i, out sb, new AsyncCallback(FinAsyncFuncOut),string.Format(“objectstate_{0}”, i));

// Una vez realizada la invocación asíncrona, se lanza un nuevo thread que ejecutará el método
// objetivo del delegado -en este caso ‘AsyncFuncOut’- en segundo plano. Cuando acabe se llamará
// a la función definida como AsyncCallBack, en este caso ‘FinAsyncFuncOut’.

}

// Marco un punto por segundo como prueba de que la aplicación puede
//seguir haciendo cosas mientras las operaciones asíncronas terminan.

while (true)
{

Console.Write(‘.’);
System.Threading.
Thread.Sleep(500);

}
Console.ReadKey();

}

/// <summary>
/// Método que se ejecutará de forma asíncrona para el segundo ejemplo.
/// </summary>
/// <param name=”parametro”>Cadena de entrada.</param>
/// <param name=”sb”>Parámetro de salida.</param>
private static void AsyncFuncOut(string p1, int p2, out StringBuilder sb)
{

// Aquí ya podriamos trabajar con los parámetros de entrada y entrada/dalida.
// Recordad que el uso de ‘out’ nos obliga a que inevitablemetne la variable
// quede asignada antes de abandonar el método. También vale igualarla a null.
sb = new StringBuilder();

sb.AppendFormat(“{0} en AsyncFuncOut.”, p1);
Console.WriteLine(sb);

// Para ejemplificar como se ejecutan de forma arbitraria, meteremos un tiempo de espera
// aleatorio en cada función.
// Haremos un sleep entre 5 y 10 segundos.

Random rndm = new Random(p2);
System.Threading.
Thread.Sleep(rndm.Next(5000, 10000));

// Al finalizar el método, se ejecuta el AsyncCallBack que indicamos en la llamada a
// .BeginInvoke, en este caso ‘FinAsyncFunc’. Si se diese alguna excepción no
// manejada seria en ‘FinAsyncFunc’ y no aqui donde nos saltaria.

}

/// <summary>
/// Método que se ejecutará al finalizar la tarea asíncrona del primer ejemplo.
/// </summary>
/// <param name=”IA”>IAsyncResult</param>
private static void FinAsyncFuncOut(IAsyncResult IA)
{

// Si en el transcurso de la ejecución asíncrona ocurriese alguna excepción no
// manejada (fuera de uno de nuestros try-catch) la recibiramos aqui, por lo que
// es importante siempre finalizar la invocación dentro de un try-catch.

try
{

// En el .EndInvoke obtendremos los parámetros configurados de salida que
// usamos en la llamada a .BeginInvoke, y obtendremos el objeto con el que hemos
// trabajado en el método asíncrono.

StringBuilder sb;
AsynCallOut.EndInvoke(
out sb, IA);

// Entre las propieades de un IASyncResult caben destacar:
// .AsyncState : Devuelve el ObjectState que indicamos cuando realizamos la
// invocación asíncrona.

// .IsCompleted: Devuelve True si esta completada.

// .AsyncWaitHandle: WaitHandle para esperar al final de la ejecución del método.
// .WaitOne(timeout, false): Bloquearia el thread actual esperando
// a la finalización del método con timeout de los milisegundos que
// queramos.

Console.WriteLine(“Fin de AsyncFunc con resultado: ‘{0}’ con objectState : ‘{1}’”,sb, IA.AsyncState);

}
catch (Exception Ex)
{

Console.WriteLine(“EX:{0}\n\n{1}”, Ex.Message, Ex.StackTrace);

}

}

El resultado del ejemplo, podría ser este:

Prueba 1.0 en AsyncFuncOut.

Prueba 1.1 en AsyncFuncOut.

Prueba 1.2 en AsyncFuncOut.

Prueba 1.3 en AsyncFuncOut.

Prueba 1.4 en AsyncFuncOut.

Fin de AsyncFunc con resultado: ‘Prueba 1.1 en AsyncFuncOut.’ con objectState : ‘objectstate_1′

Fin de AsyncFunc con resultado: ‘Prueba 1.3 en AsyncFuncOut.’ con objectState : ‘objectstate_3′

Fin de AsyncFunc con resultado: ‘Prueba 1.0 en AsyncFuncOut.’ con objectState : ‘objectstate_0′

Fin de AsyncFunc con resultado: ‘Prueba 1.2 en AsyncFuncOut.’ con objectState : ‘objectstate_2′

Fin de AsyncFunc con resultado: ‘Prueba 1.4 en AsyncFuncOut.’ con objectState : ‘objectstate_4′

Para la siguiente entrega, mostraré como trabajar con los objetos IAsyncResult y controlar el flujo de hilos asíncronos.

1 comentario »

  1. [...] en: Modelo Asíncrono, Recurso MSDN, .NET, C# — vtortola @ 4:36 pm Como continuación de Modelo Asíncrono. Parte I, invocación, hoy ejemplificaré como controlar el flujo de operaciones asincrónas asegurando el que no haya [...]

    Pingback por Modelo Asíncrono. Parte II, control. « WhatTheFuckException was thrown — Abril 29, 2007 @ 5:03 pm


Canal RSS de los comentarios de la entrada. URI para TrackBack.

Deja un comentario

Debes ser Sesión como para publicar un comentario.

Blog de WordPress.com.