Anteriormente, estuvimos hablando sobre La Diferencia entre método Síncrono y Asíncrono. La cual básicamente esta relacionado al comportamiento y ejecución de los programas; En el caso de los métodos síncronos la invocación espera el resultado. Por su parte, los asíncronos realizan la invocación y la ejecución no se bloquea, aunque el método esté esperando algún parámetro o dato.

Dicho esto, aún quedan algunos cabos por atar que serán abarcados en este artículo. Tales como: ¿Qué es un callback?, ¿por qué se definen?, y finamente, formas de implementar los patrones para realizar las operaciones asincrónicas.

Es importante saber que cuando utilizamos los métodos asíncronos, se presentan dos situaciones:

  1. No bloqueamos la ejecución de la aplicación.
  2. La llamada retorna sin realizarse ninguna acción y como consecuencia no retorna un resultado.

Para solucionar la problemática del punto dos, tendremos que recurrir al uso de callback (Retrollamada). Una retrollamada es un delegado para procesar los resultados de una operación asincrónica en un subproceso independiente.

Al igual que en el articulo anterior, los fragmentos de código que estaremos presentando provienen de C#. Teniendo esto presente, podemos decir que en este lenguaje existen dos formas de lidiar con este escenario y esto posible mediante:

  • Utilización de un delegado AsyncCallback para procesar los resultados de la operación asincrónica en un subproceso independiente.
  • Empleo de la propiedad de IsCompleted proveniente de  IAsyncResult, devuelto por el método de InicioName de la operación asincrónica, para determinar si la operación se ha completado.

Convirtiendo en Códigomagic-wand

  • Utilización de un delegado AsyncCallback:

codigo1

A continuación les mostraré un modelo de código donde se muestran distintas maneras de llamar al mismo método de ejecución prolongada, como el TestMethod de forma asíncrona.

En este ejemplo de código siguiente se muestra la definición de TestMethod y el delegado denominado AsyncMethodCaller que se puede utilizar para llamar a TestMethod de forma asíncrona.

codigo2

  • Aplicando la propiedad de IsCompleted de IAsyncResult:

En su formas mas sencilla esta es la propiedad:

codigo3

Sin embargo, el siguiente ejemplo expone de manera práctica la implementación de esta propiedad y consta de dos clases: La clase que contiene el método que se invoca de forma asíncrona y la clase que contiene el Main método que realiza la llamada.

codigo4

La manera más sencilla de ejecutar un método de forma asincrónica es, empezar a ejecutar el método llamando al método BeginInvoke del delegado, asignar alguna tarea en el subproceso principal y, a continuación, llamar al método EndInvoke del delegado. EndInvoke podrían bloquear el subproceso que realiza la llamada porque no vuelve hasta que no se completa la llamada asincrónica. Ésta es una buena técnica para utilizarla con operaciones de archivos o red. Dado que EndInvoke podría mantener un bloqueo, nunca se debe llamar a este método desde los subprocesos que dan servicio a la interfaz de usuario.

 codigo5

 

Los patrones para realizar las operaciones asincrónicas

Muchas aplicaciones llaman a métodos de forma asincrónica porque permiten que la aplicación siga realizando un trabajo útil, mientras la llamada al método se ejecuta. Los servicios y clientes de Windows Communication Foundation (WCF) pueden participar en llamadas de operación asincrónica en dos niveles distintos de la aplicación, que proporcionan a las aplicaciones de WCF aún más flexibilidad para maximizar el rendimiento equilibrado con interactividad.

Implementar una operación de servicio asincrónica

Las operaciones asincrónicas se pueden implementar mediante uno de los tres métodos siguientes:

  1. El patrón asincrónico basado en tareas
  2. El patrón asincrónico basado en eventos
  3. El patrón asincrónico de IAsyncResult

 

Patrón asincrónico basado en tareas

En nuestro primer caso, patrones basado en tareas (TAP Task-based Asychronus Pattern) está basado en Task<TResult> tipos en System.Threading.Task “namespace”, la cual es usado para representar arbitrariamente las operaciones asincrónicas. Un método asíncrono basado en TAP tiene permitido realizar una pequeña cantidad de trabajo sincrónicamente antes de retornar la tarea resultante. El trabajo debe ser mantenido en la cantidad necesaria, ejecutando operaciones como, validación de argumentos e inicialización de operaciones asíncronas. Es probable que los métodos asíncronos sean invocados desde los subprocesos de la interfaz de usuario y por lo tanto cualquier trabajo de larga duración en la parte anterior síncrona de un método asíncrono podría perjudicar la capacidad de respuesta.

El patrón asincrónico basado en tareas es la forma recomendada de implementar operaciones asincrónicas porque es la más sencilla. Para usar este método, implemente simplemente la operación de servicio y especifique un tipo de valor devuelto de Task<T>, donde T es el tipo devuelto por la operación lógica. Por ejemplo:

codigo6

La operación SampleMethodTaskAsync devuelve Task<string> porque la operación lógica devuelve una cadena. Sin embargo, cuando se usa el patrón asincrónico basado en tareas, se puede iniciar una T:System.AggregateException si se produce una excepción mientras se espera la finalización de la operación. Esta excepción puede producirse en el cliente o servicios.

Patrón asincrónico basado en eventos

Todo servicio que admita el modelo asincrónico basado en eventos tendrá una o varias operaciones denominadas MethodNameAsync. Estos métodos pueden reflejar versiones sincrónicas, que desempeñan la misma operación en el subproceso actual. La clase también puede tener un evento MethodNameCompleted y un método MethodNameAsyncCancel (o simplemente CancelAsync). Un cliente que desea llamar a la operación, definirá un controlador de eventos para que se llame cuando la operación se complete.

El fragmento de código siguiente muestra cómo declarar operaciones asincrónicas mediante el patrón asincrónico basado en eventos.

 

codigo7

Patrón asincrónico de IAsyncResult

Una operación de servicio se puede implementar asincrónicamente mediante el patrón de programación asincrónico .NET Framework y marcando el método <Begin> con la propiedad AsyncPattern establecida en true. En este caso, la operación asincrónica se expone en metadatos de la misma manera que una operación sincrónica: se expone como una operación única con un mensaje de solicitud y un mensaje de respuesta correlativo. Los modelos de programación de cliente tienen entonces una opción; Pueden representar este patrón como una operación sincrónica o como una asincrónica, siempre que se origine un intercambio de mensajes solicitud-respuesta cuando se invoque el servicio.

En general, con la naturaleza asincrónica de los sistemas, no se debería adoptar la dependencia de los subprocesos. La manera más fiable de pasar los datos a varias fases del procesamiento de envío de la operación es usar extensiones.

  • En su contrato de servicio, declare un par de métodos asincrónicos según las instrucciones de diseño asincrónico de .NET. El método Begin toma un parámetro, un objeto de devolución de llamada y un objeto de estado, y devuelve un IAsyncResult y un método End correspondiente que toma System.IAsyncResult y devuelven el valor devuelto.

 

  • Marque el método Begin del par de métodos asincrónicos con el atributo ServiceModel.OperationContractAttribute y establezca la propiedad OperationContractAttribute.AsyncPattern en true. Por ejemplo, el código siguiente realiza este y el paso anterior.

codigo8

  • Por último, Implemente el par de método Begin/End en su clase de servicio según las       instrucciones de diseño asincrónicas. Por ejemplo, el siguiente ejemplo de código muestra una implementación en la que una cadena se escribe en la consola en porciones Begin y End de la operación de servicio asincrónica y el valor devuelto de la operación End se devuelve al cliente.

codigo9

Recordatorios Importanteslight-bulb

Finalmente, tres recordatorios importantes respecto al uso de métodos asincrónicos son los siguientes:

  • Los métodos async requieren de la palabra clave await en su cuerpo, o nunca producirán el resultado deseado.
  • async void solo debe ser usado para controlar eventos.
  • Tenga cuidado al usar lambdas asíncronas en expresiones LINQ, las expresiones Lambda en LINQ utilizan la ejecución diferida, lo que significa que el código puede terminar ejecutándose en un momento en el que no lo esperes. La introducción de tareas de bloqueo en esto, puede resultar fácilmente en un punto muerto si no se escribe correctamente.

Espero que este articulo haya aportado las piezas faltantes del rompecabezas, sobre el uso de métodos asíncronos y que sea de utilidad. Si les ha gustado no olviden compartir y dejarme saber que piensan al respecto.