C#5 Tomando una cerveza con Feynman (o await 2a parte)

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:

image

Simplemente IrAlBareto() y luego IrAComprarRopa().

El código de IrAlBareto(), que es un método async, es tal y como sigue:

image

image

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():

image

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:

image

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:

  1. Await realiza una espera no bloqueante sobre un objeto awaitable (una Task).
  2. Mientras dura la espera de await, el método async (que contiene la llamada a await) retorna a su llamador
  3. 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

C# 5: Async / Await

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<T>.

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<T> desde este método. Así se sencillo. Dejemos las cosas claras (al contrario que el chocolate): Devolver un Task NO convierte el método en asíncrono. Es la propia Task que es asíncrona. Podemos ver una Task como un delegate (o sea un método) que puede ser ejecutado de forma asíncrona. Trasladando eso de nuevo al ejemplo del bar, cuando yo pido la cerveza al camarero, le he encargado esta tarea y la he puesto en marcha. En términos de C# cuando llamo al método ServirCerveza de la clase camarero, este método me devuelve una Task<Cerveza>, que representa la tarea que he encargado al camarero. Luego yo debo poner en marcha esa tarea (con lo cual el camarero irá efectivamente a buscarla) y cuando toque esperarnos llamaremos a await sobre el objeto Task<Cerveza>. El resultado de llamar a await sobre una Task<Cerveza> es precisamente… un objeto de la clase Cerveza (mi cerveza para ser más exactos).

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:

image

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<Cerveza>:

image

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<Cerveza>. Como comenté una Task es parecido a un delegate sólo que es asíncrona, y en este caso una Task<T> se inicializa a partir de una Func<T> que le indica precisamente que se tendrá que hacer cuando se inicie la tarea. En nuestro ejemplo el camarero debe ir al almacén (que está lejos y es una operación que tarda un poco) y devolver la cerveza que se ha pedido.

Vayamos ahora a lo que ocurre cuando se pulse el botón:

image

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<Cerveza>. En este momento la ejecución de la tarea del camarero todavía no ha empezado. Cuando llamamos a task.Start() empieza la ejecución de dicha tarea de forma asíncrona. Y a la vez, yo y mi amigo seguimos hablando de cosas de la vida. El código de HablandoDeLaVida() se ejecuta concurrentemente con el de la tarea definida en ServirCerveza. Al final mi amigo propone el brindis y como no tengo cerveza nos esperamos, usando await sobre el objeto Task<Cerveza> que había recibido. Con esto nos esperamos a que finalice dicha tarea y obtenemos el resultado (que dado que era una Task<Cerveza> el resultado es una Cerveza). Y listos.

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<T>, entonces en la implementación del método async no es necesario que creeis la Task<T>, sino que podeis devolver directamente un objeto de tipo T. Es decir, en nuestro ejemplo el siguiente código:

image

Compila correctamente. El método devuelve una Task<Cerveza> pero a diferencia de antes no tengo que crearla explicitamente. Y eso es debido al uso de async en la declaración. Eso supongo que es porque en muchos casos se van a ir encadenando métodos asíncronos y así nos ahorramos el tener que definir las Task<T> de forma explícita. Pero insisto, no os confundáis: es Task<T> lo que hace que el método pueda ser llamado de forma asíncrona, no async. De hecho si os fijáis en la imagen el nombre del método está subrayado en verde y eso es porque el compilador me está avisando que he declarado un método async… que no usa await en ningún momento, cosa que no tiene sentido (porque la única funcionalidad de async es permitir que el método use await).

Mi primera aplicación en MetroUI

Muy buenas! Como muchos otros he descargado el Windows 8 Developers Preview, y he empezado a jugar con la nueva API de WinRT para la creación de aplicaciones basadas en MetroUI.

Vamos a ver como realizar una aplicación MetroUI usando C# que simplemente nos muestre las imágenes que tenemos en la carpeta de “Mis Imágenes”.

Para ello, abrimos el Visual Studio 2011 Express que viene con el Windows 8 Developers Preview y seleccionamos el tipo de proyecto de tipo “Windows Metro Style –> Application”:

image

Con eso VS2010 nos genera el esqueleto del proyecto inicial.

¡Hey eso es WPF!

Pues no. Aunque sin duda se le parece mucho. Veamos, por un lado tenemos la definición de la interfaz en XAML. Si tecleamos un poco, vemos que nuestros controles de WPF (o Silverlight) están aquí:

image

Tenemos TextBlock, Button, Grid, StackPanel… con las mismas propiedades y las mismas extensiones de XAML que nos podemos encontrar en WPF. Si no son las mismas son muy, muy parecidas. Y esa es la primera lección que extraemos: el conocimiento que hemos adquirido desarrollando con WPF o Silverlight no está perdido. Así pues, tranquilos por este lado: no empezamos de cero!

En mi caso he diseñado una página muy cutre que se compone básicamente de un botón, una etiqueta y una lista. Cuando se pulse el botón la lista debe mostrar los nombres y un thumbnail de las imágenes que tenemos en “Mis Imagenes”. Esa es la idea. La definición de la vista es muy simple:

image

Los que hayáis desarrollado en WPF o Silverlight no veréis nada nuevo. Insisto, todos los conceptos que conocemos están aquí. Estilos, recursos, templates, bindings… Todo funciona exactamente igual.

WinRT la nueva API que está detrás…

Aunque este XAML parezca de WPF o Silverlight, realmente no estamos usando WPF ni Silverlight. Eso significa que por detrás, es decir en el código C#, tenemos una nueva API que si que nos va a tocar aprender a utilizar… Pero es que si no… donde estaría la diversión?

Bueno, veamos lo primero que quiero es recorrer las imágenes de la carpeta de “Mis Imagenes” cuando se pulse el botón. Eso, hasta ahora, lo conseguiría usando el método GetFiles de la clase System.IO.Directory, p.ej. Ahora, no: olvidaos de todo esto. De hecho, si en el código C# tecleáis System.IO:

image

veréis que NO sale la clase Directory. No existe! Podéis pensar que a lo mejor falta alguna referencia, pero no… Simplemente no tenemos disponible esta clase. Así que debemos usar la nueva API WinRT que se encuentra colgando del namespace Windows.

Y esa nueva API tiene una característica muy especial: está diseñada de un modo muy asíncrono. Muchas de sus clases tienen métodos cuyo nombre termina en Async() y que son asíncronas. Por suerte en C#5 vamos a disponer de las palabras clave async y await que hacen que llamar a métodos asíncronamente sea lo más fácil del mundo. Ya veréis vais a usar await y async constantemente…

Bien, a lo que íbamos, cuando se pulse el botón quiero que:

  1. El TextBlock de estado diga “Obteniendo”.
  2. Se obtengan las imágenes que hay en mis imágenes.
  3. Y se enlacen con la ListBox para que se muestren.

Y el código es el siguiente:

image

Veis lo que os decía de async y await? Bueno… a ver, este código es muy simple, lo que hace es lo siguiente:

  1. Pone el texto “Obteniendo” en nuestro TextBlock de estado
  2. Llama al método DisplayImagesAsync(). Método que se ejecutará asíncronamente.
  3. Cuando el método termine, se ejecutará el código que está a continuación del await, es decir pondrá el TextBlock a blanco, para indicar que ya ha terminado.

En este caso, realmente no hay asincronidad. Me explico: el método DisplayImagesAsync() está pensado para que pueda ser usado asíncronamente, pero nosotros no hacemos nada entre que llamamos el método y nos esperamos (await) a que termine. Si entre la línea var displayImagesTask = DisplayImagesAsync() y la siguiente (await displayImagesTask) yo hubiese colocado código, este código se ejecutaría en paralelo al código del método DisplayImagesAsync(). Esta es la potencia brutal de async/await: facilitan hasta el absurdo la creación de métodos que pueden ser invocados asíncronamente y la espera para que terminen esos métodos.

Bueno… veamos el método DisplayImagesAsync(). Para empezar dicho método debe obtener acceso a la carpeta de “Mis Imagenes”. Para ello usamos la clase KnownFolders de Windows.Storage:

image

Con eso en picsFolder tenemos un objeto que nos permitirá recorrer la carpeta de “Mis Imágenes”. Para ello tiene un método GetItemsAsync() que nos devuelve una lista con todos los elementos. Así que, lo invocamos:

image

Esta forma de usar await es muy común y en el fondo es lo mismo que hemos hecho antes (cuando hemos llamado a DisplayImagesAsync) pero en una sóla linea: invocar el método asíncrono, esperarnos a que termine y en pics tenemos el resultado 🙂

Este resultado es un enumerable con todos los items de la carpeta. Eso incluye ficheros y directorios. Lo que vamos a hacer ahora es iterar por todos los ficheros y por cada fichero obtener un thumbnail junto con su nombre y su ruta:

image

Listos! Con esto rellenamos la lista images (una lista dinámica) con los datos (nombre, ruta y thumbnail) de las imágenes que tengamos. Nos queda una pieza para verlo todo y es el método GetBitmapData.

El método GetThumbnailAsync no devuelve directamente un bitmap con el thumbnail, sino que devuelve un objeto (de la clase StorageItemThumbnail) a partir del cual podemos obtener un stream a los datos que representan el bitmap del thumbnail. Pero nosotros queremos algo que sea un ImageSource (para enlazarlo a la propiedad Source del DataTemplate de la ListBox). Y eso que necesitamos es un objeto de la clase BitmapImage. Por suerte es muy fácil obtener un BitmapImage a partir de un StorageItemThumbnail:

image

Y listos! Con esto lo tenemos todo ya hecho… sólo nos queda enlazar la lista images con nuestra ListBox, y eso lo conseguimos con este código (al final de DisplayImagesAsync), que resultará muy familiar a quien haya desarrollado con WPF o Silverlight:

image

Y listos! Con esto conseguimos mostrar las imágenes que tenga el usuario en la carpeta “Mis Imágenes”:

image

Hemos realizado nuestra primera aplicación MetroUI! 🙂

Ah sí! Permisos, permisos, permisos

Que me olvido! Las aplicaciones MetroUI tienen asignado un sistema de seguridad, donde tienen que declarar exactamente que permisos necesitan. Esos permisos se mostraran al usuario cuando este quiera ejecutar la aplicación (o la compre desde el nuevo Windows Store). Para ello es necesario editar el archivo Package.appxmanifest y allí poner los permisos necesarios. Visual Studio 2011 viene con un editor para este archivo. En nuestro caso, debemos pedir específicamente permiso para acceder a la carpeta de imágenes del usuario:

image

Tenemos que ir a “Capabilities” y marcar la checkbox de Picture Library Access.

Ahora sí, que ya lo tenemos todo! 😉

Un saludo!

PD: El código en este post son imágenes porque estoy posteando desde el propio Win8 y no tengo ningún plugin de código instalado en el Live Writer

PD2: He dejado el proyecto (de Visual Studio 2011 Developers Preview) en mi carpeta de skydrive. Lo podeís descargar desde aquí: MyFirstApp (código fuente)

PD3: No toméis esa aplicación como una guía de buenas prácticas ni nada parecido! Este post es simplemente para compartir mi experiencia de “desvirgamiento” en WinRT 😛 😛 😛