Programación Asíncrona antes de C#5 – Parte 4/4

En este artículo final de la serie por fin llegamos a C#5 y veremos sus dos palabras claves que tanta confusión y expectativa generaron entre muchos desarrolladores, si, las palabras clave Async y Await. En este último artículo hablaremos sobre qué pasa con esta nueva versión del lenguaje y que nos trae de nuevo para el desarrollo de tareas asíncronas.

  • Async no hace que el método sea asíncrono:

La primera cosa que quiero empezar por aclarar es que marcar un método como async NO HACE al método asíncrono, para demostrarlo continuemos con nuestro ejemplo de la sumatoria, veamos el siguiente código:

        private void BtnCalcAsinAsyncAwaitClick(object sender, EventArgs e)
        {
            var resutado = SumatoriaAsyncAwait(2, 123456789123456);

        }
        public async long SumatoriaAsyncAwait(int numero, long nVeces)
        {
            long resultado = 0;
            for (int i = 1; i <= nVeces; i++)
            {
                resultado += numero;
            }
            return resultado;
        }

Al compilarlo recibiremos el error The return type of an async method must be void, Task or Task<T>, esto porque un método async solo puede retornar void, Task o Task<T>, Si! Task nuestras vieja conocida amiga de la TPL… entonces vemos que el procesamiento asíncrono REALMENTE se sigue haciendo con nuestra buena amiga la TPL, pero entonces para que marcamos un método como async? pues bien, esta viene a resolvernos un problema que teníamos de antes y es el tema de la sincronización de métodos. Ni más ni menos, y viene a resolverlo con su aliado inseparable… await

  • El problema de la Sincronización:

Como veíamos en los ejemplos anteriores a TPL el manejo del Call Back sí que era complicado, pues teníamos que recuperar el valor devuelto en otro método y para trabajar con este se hacía muy tedioso. Con la llegada de la TPL vimos un método maravilloso, el ContinueWith() pues podíamos manejar el Call Back en el mismo método llamador e incluso usar variables que estuvieran por fuera del contexto del delegado.

Otro problema lo encontramos con la sincronización de threads, un ejemplo claro de esto es cuando intentamos modificar la interfaz de usuario desde un método que este corriendo en otro thread. Como lo muestra el siguiente código:

        private void BtnCalcularSumatoriaTaskClick(object sender, EventArgs e)
        {
            var tarea = SumatoriaAsync(int.Parse(txtNumero.Text), long.Parse(txtNVeces.Text));
            tarea.ContinueWith(x =>
                                   {
                                       lbResultadoSuma.Text = x.Result.ToString();
                                   });
        }

Si hacemos un análisis vemos donde inicia la aplicación y como pasa a otro hilo:

Luego de esto recibimos una bonita excepción.

Para solucionar esto podíamos recurrir a cosas como Invoke.

  • Async – Await al rescate:

Teniendo presente entonces estos antecedentes y continuando con nuestra serie, veamos el ejemplo de la sumatoria con nuestras nuevas dos palabras.

        private async void BtnCalcAsinAsyncAwaitClick(object sender, EventArgs e)
        {
            var task = SumatoriaAsyncAwait(2, 1234567890);
            long resultado = await task;
            int suma = 1 + 1;
            int resta = suma - 3;
            MessageBox.Show(resta.ToString());
            lbResultadoSuma.Text = resultado.ToString();
        }

        public Task<long> SumatoriaAsyncAwait(int numero, long nVeces)
        {
            return Task.Factory.StartNew(() =>
                                             {
                                                 long resultado = 0;
                                                 for (int i = 1; i <= nVeces; i++)
                                                 {
                                                     resultado += numero;
                                                 }
                                                 return resultado;
                                             });
        }

Como vemos usamos async en el método llamador y NO en el que será asíncrono, el método asíncrono lo seguimos trabajando como lo hacíamos con TPL, de hecho para poder hacer await sobre el callback necesitamos que el método sea una Task :D. Y como se muestra en el ejemplo, await no es una espera bloqueante, pues podemos seguir ejecutando código que este después de esté.

Un aspecto importante para resaltar, es que Async – Await nos intentara devolver al hilo desde el que hizo la llamada siempre que sea posible, por eso en este ejemplo podemos modificar la UI sin necesidad de Invoke o cualquier otra técnica y no recibiremos esa molesta excepción.

Más información en estas dos entradas del buen Eduard Tomas:

C# 5: Async / Await

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

Bien hasta aquí este articulo y esta serie.

Anuncios
Programación Asíncrona antes de C#5 – Parte 4/4

5 comentarios en “Programación Asíncrona antes de C#5 – Parte 4/4

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s