En el post anterior vimos como gracias a C# 5 y las nuevas palabras clave async y await el uso de métodos asíncronos era tan sencillo como ir al bar y tomarnos una cerveza. Como resumen del post vimos que async nos permitía indicar que un método quería realizar llamadas asíncronas y await nos permitía esperarnos al retorno de una llamada asíncrona. Si no has leído el post, antes de leer este échale un vistazo.
En el post de ayer hice una simplificación, porque no quería liar las cosas más de la cuenta y total sólo iba a tomarme una cerveza. Hoy para mi desgracia, y para la vuestra, he quedado con Richard Feynman para tomarme esa misma cerveza… No interpretéis mal lo de “desgracia”, honestamente si pudiese elegir alguna personalidad de todos los tiempos con los que poder sentarme en una terraza y hablar de temas varios él estaría en uno de los primeros lugares de la lista.
Supongamos el mismo ejemplo de ayer. Es decir, yo me voy al bar,vistiendo mi jersey rojo y allí me encuentro al bueno de Richard, tomando una cervecilla. Me uno a él, pido una cerveza (o sea, le encargo al camarero la tarea de que vaya al almacén a buscar una cerveza y me la traiga) y mientras esperamos hablamos de cosas de la vida. En esto, Richard que es un poco despistado y no se ha dado cuenta de que todavía no tengo mi cerveza, propone un brindis. Pero como todavía no tengo mi cerveza nos esperamos a que el camarero me la traiga. Cuando el camarero nos trae la cerveza, Richard sonríe y me dice que el nuevo jersey azul que me he comprado es muy bonito. A eso yo me miro y efectivamente veo que llevo un jersey azul nuevo. Pero… no estaba yo esperando a que el camarero me trajera la cerveza?? No recuerdo haber ido a comprar ningún jersei azul… o sí?
¿Que ha ocurrido? La verdad es que Richard me lo explicó, a su manera claro, usando su teoría de las múltiples historias, y resumiendo eso es más o menos lo que ocurrió…
La clave del meollo es que cuando nos esperamos a que el camarero nos trajera la cerveza no nos quedamos sin hacer nada. Al contrario, cada uno de nosotros continuamos haciendo las tareas que teníamos pendientes hacer. En mi caso, comprarme un jersei rojo (en el de Richard probablemente revolucionar la física moderna con algún nuevo descubrimiento). Luego, en el momento en que el camarero llega con mi cerveza, tanto Richard como yo continuamos haciendo lo que teníamos que hacer cuando yo tuviese mi cerveza: el brindis. Ya… eso es lo que ocurre cuando hablas con genios de la talla de Feynman: te dejan el cerebro hecho fosfatina.
Y ahora, por salud mental, permitidme que abandone el ejemplo de la cerveza y hable en términos de programadores, a ver si nos entendemos mejor. La clave es que await no realiza una espera bloqueante (si lo hiciera convertiríamos la tarea por la que esperamos en una llamada síncrona). Lo que realmente hace await es que el método async devuelve a su llamador justo en este momento. I el resto del método async (el código que sigue al await) se ejecutará cuando la tarea por la que está esperando await ha terminado.
Imaginad el siguiente código que representa un día en mi vida:
Simplemente IrAlBareto() y luego IrAComprarRopa().
El código de IrAlBareto(), que es un método async, es tal y como sigue:
Me voy al bar, hablo de cosas de la vida con Richard, pido mi cerveza al camarero, me espero por ella con await y luego hacemos un brindis. Ahora viene la clave: lo que ocurre al llamar a await es que el método IrAlBareto retorna a su llamador (el método UnDiaEnMiVida). Con lo que la ejecución del sistema continúa con la llamada a IrAComprarRopa():
Finalmente, cuando el método PedirCerveza, que es por el cual estábamos haciendo await termina, se continua ejecutando el código que sigue al await, es decir la llamada al método Brindis
Esa es la salida que genera el programa:
He dejado el código del proyecto en mi carpeta de Skydrive – AsyncAwait2. Es un proyecto console application de VS2011 Developers Preview.
Así pues recordad:
- Await realiza una espera no bloqueante sobre un objeto awaitable (una Task).
- Mientras dura la espera de await, el método async (que contiene la llamada a await) retorna a su llamador
- Cuando la espera de await ha terminado, se ejecuta el resto del código del método async que contenía el await (exacto… es como si el resto del código que sigue al await fuese el callback!).
Un saludo a todos… y felices cervezas! xD