Nota: Este post ha sido importado de mi blog de geeks.ms. Es posible que algo no se vea del todo "correctamente". En cualquier caso puedes acceder a la versión original aquí
Muy buenas! Como dije en el post anterior estoy trasteando un poco con la Developers Preview de Windows 8 y la nueva API WinRT para crear aplicaciones Metro. El tema está en que esta nueva API está diseñada de forma muy asíncrona. Por suerte en C# 5 el uso de métodos asíncronos se ha simplificado mucho gracias a dos nuevas palabras clave: async y await. Y dado que, creedme, vais a tener que usarlas en cuanto os pongáis con WinRT me he decidido escribir este post para comentarlas un poco 🙂
async
Esta palabra clave se aplica a la declaración de un método pero, contra lo que se suele pensar por primera vez no declara que un método se ejecuta asíncronamente. La palabra clave async lo que indica es que este método se quiere sincronizar con métodos que se ejecutarán de forma asíncrona. Si no usáis async podréis seguir llamando métodos de forma asíncrona (de hecho hasta ahora lo veníamos haciendo), lo que no podréis hacer (de forma trivial) es sincronizaros con este método asíncrono. ¿Que significa sincronizarse con un método asíncrono? Fácil: esperar a que termine. Ni más, ni menos.
Es como si yo me voy a un bar y allí me encuentro a un colega. Me siento con él, y pido una cerveza, de la misma que está tomando él. Mientras me la traen hablamos de temas de la vida hasta que mi colega propone un brindis. Pero todavía no ha llegado el camarero con mi cerveza, así que yo y mi amigo nos quedamos esperando sin hacer nada a que el camarero llegue (sí, los dos somos un poco nerds). Cuando el camarero llega, hacemos el brindis y seguimos hablando.
Declarar un método como async es requisito indispensable para poder usar await.
await
Esa palabre clave es la que permite que un método que ha llamado a otro método asíncrono se espere a que dicho método asíncrono termine. Usando de nuevo el ejemplo del bar, cuando mi amigo dice de hacer el brindis debemos esperarnos a que llegue el camarero con mi cerveza.
La clave de todo es entender que desde el momento en que yo encargo mi cerveza al camarero (llamada al método asíncrono) hasta el momento en que decidimos que nos debemos esperar yo (con mi amigo) hemos estado haciendo otras cosas (hablando de la vida). Eso, de nuevo trasladado a código fuente, significa que entre la llamada al método asíncrono y el uso de await habrá más líneas de código fuente. Por lo tanto no usamos await cuando llamamos al método asíncrono, lo hacemos más tarde cuando queremos esperarnos a que dicho método termine (y recoger el resultado, es decir mi cerveza).
Así pues… sobre que aplicamos await? Pues todo método que quiera ser ejecutado asíncronamente debe devolver un objeto especial, que sea (ojo con la originalidad de los ingleses) awaitable. Sobre este objeto, es sobre el que llamaremos a await para esperarnos a que el método asíncrono finalice y a la vez obtener el resultado. ¿Y que es un objeto awaitable? Pues un conocido de la TPL que viene con .NET 4: Un objeto Task o su equivalente genérico Task
Métodos asíncronos
Para declarar un método que pueda ser llamado de forma asíncrona, lo único que debemos hacer es devolver un Task o Task
Código, código, código
Vamos a ver el ejemplo de la cerveza implementado en C# para que nos queden los conceptos más claros 😉
Para ello, dado que en la versión de VS2011 que viene con la Developers Preview de Win8 no podemos crear aplicaciones de consola, vamos a crear una aplicación Metro. En la vista principal pondremos 3 texblocks que nos permitirán ver cuando pedimos la cerveza al camarero, cuando nos la trae y como”hablamos” entre medias. El código XAML es muy simple:
Lo siguiente que necesito es una clase que represente a mi Camarero y un método que me permita pedirle una cerveza de forma asíncrona. Recordad que entonces debo declarar el método que me devuelva, no un objeto de Cerveza sino un objeto de Task
El método ServirCerveza de la clase Camarero espera un parámetro (el tipo de cerveza se quiere) y lo que hace es devolver una Task
Vayamos ahora a lo que ocurre cuando se pulse el botón:
Ponemos en txtInicial la fecha y hora en que pedimos la cerveza. Y llamamos al método ServirCerveza del camarero. Este método retorna en el acto y nos devuelve una Task
ra una Task
Observad como la función Button_Click ha sido declarada como async para indicar que quiere llamar a métodos asíncronos y usar await para sincronizarse con ellos (esperar a que terminen).
El uso de async y await, junto con la clase Task de la TPL hace que en C#5 el crear y consumir métodos asíncronos sea tan fácil como ir al bar y pedir una cerveza! 🙂
Un saludo!
PD: Un comentario final, que quiero poner por completitud del post. Si declaráis un método async (porque quiereis hacer await sobre algún método asíncrono) pero a la vez este método async puede ser llamado de forma asíncrona y por lo tanto devuelve una Task
Compila correctamente. El método devuelve una Task