DE .NET, SQLSERVER Y MÁS, APRENDE CONMIGO!✔

Desarrollo de todo tipo de aplicaciones y Administración de Base de datos con Tecnología Microsoft


UNETE

Operaciones asíncronas en C#

0

 

Operaciones asíncronas

Una computadora tiene una cantidad fija de procesadores y cada uno de estos procesadores puede ejecutar solo una operación a la vez, llamémosle hilo a esta operación. Cada hilo en una aplicación está programado para correr en el procesador por un periodo de tiempo.

Si un código realiza alguna acción de Entrada/Salida el hilo se suspende hasta que el dispositivo ha completado su trabajo. Si se tiene una tarea de muy larga duración se la puede iniciar en un hilo de trabajo separado y obtener el resultado de la operación una vez que la tarea se haya completado. Mientras que el hilo separado se ejecuta la aplicación puede realizar otras tareas que no estén relacionadas con la tarea de larga duración. Así, podemos aislar el trabajo que hacen las tareas.

La mayoría de los métodos son llamados síncronos, lo que significa que el método se completará en el hilo actual. Sin embargo, algunos métodos son llamados asíncronos lo que significa que el hilo actual inicia la ejecución del método en otro hilo y la llamada regresa inmediatamente. Los métodos síncronos son conocidos como bloqueos debido a que el hilo que llama al método no hace otro trabajo hasta que el método se completa.

namespace Threads

{

    class Program

    {

        static void Main(string\[\] args)

        {

            //Se crea un hilo que iniciará llamando al método TareaLenta

            System.Threading.Thread tarea =

                new System.Threading.Thread(

                    new System.Threading.ParameterizedThreadStart(TareaLenta));

            //Se inicia la otra tarea

            tarea.Start(900);

            //Se revisa si ya terminó la otra tarea

            if (tarea.ThreadState != System.Threading.ThreadState.Stopped)

            System.Console.WriteLine("La otra tarea sigue corriendo");

            //Se detiene el hilo actual hasta que termine la otra tarea o

            //hasta que pasen 1000 milisegundos

            tarea.Join(1000);

            //Se revisa otra vez si ya terminó la otra tarea

            if (tarea.ThreadState != System.Threading.ThreadState.Stopped)

                System.Console.WriteLine("Paso un segundo y la otra tarea sigue...");

            else

                System.Console.WriteLine("¡Por fin terminó la otra tarea!");

            System.Console.ReadLine();

        }

 

        /// <summary>

        /// Método que será llamado por un hilo que tiene una duración igual

        /// a los milisegundos indicados en parametro

        /// </summary>

        /// <param name="param"></param>

        static void TareaLenta(object parametro)

        {

            //Parámetro en forma de entero

            int lapso = (int)parametro;

            //Deteniendo la tarea por el tiempo indicado

            System.Threading.Thread.Sleep(lapso);

            System.Console.WriteLine("Esta tarea lenta ha terminado");

        }

    }

}

Para más información sobre hilos visite:\ http://msdn.microsoft.com/es-mx/library/6kac2kdh.aspx

Las modificaciones a los datos son también consumidoras de tiempo lo cual resulta en una pobre experiencia de usuario. Otra forma de usar tareas alternas con hilos es usando un objeto BackgroundWorker como se muestra a continuación.

namespace EjemploBackgroundWorker

{

    class Program

    {

        static void Main(string[] args)

        {

            //Se crea un objeto BackgroundWorker

            System.ComponentModel.BackgroundWorker tarea = new System.ComponentModel.BackgroundWorker();

            //Se genera el código que será asignado

            //al evento DoWork (la tarea asíncrona)

            tarea.DoWork += (o, parametros) =>

            {

                //Se simula un retardo de 1 segundo

                //Por ejemplo, un acceso muy tardado

                //a una base de datos

                System.Threading.Thread.Sleep(1000);

                //En el resultado ponemos cualquier cosa

                //por ejemplo la hora actual

                parametros.Result = System.DateTime.Now;

            };

            // Se recupera el resultado al completar la tarea

            tarea.RunWorkerCompleted += (o, parametros) =>

            {

                if (parametros.Error != null)

                {

                    //Pon mensaje de error

                    System.Console.WriteLine("Con errores");

                }

                else

                {

                    //Pon mensaje de éxito

                    System.Console.WriteLine("Sin errores");

                    //Se obtiene el resultado obtenido en la tarea

                    //y se imprime

                    System.Console.WriteLine(parametros.Result.ToString());

                }

            };

 

            //Se pone a funcionar la tarea

            tarea.RunWorkerAsync();

            System.Console.ReadLine();

        }

    }

}

 

Este proceso comienza a verse muy complicado ya que siempre necesitamos de un método o bloque de código que responda a los eventos “HacerTrabajo” y “TrabajoCompletado” del hilo.

 

Async - Patrón asíncrono en base a tareas

Cuando se utiliza el patrón asíncrono en base a tareas del Framework .NET 4.5 (TAP por sus siglas en inglés) los métodos asíncronos devuelven un objeto Task representando la tarea. Utiliza los tipos Task y Task<TResult> del espacio de nombre System.Threading.Tasks para representar operaciones asíncronas arbitrarias.

Cuando se invoca una tarea y se espera su finalización se utiliza la palabra clave await en la llamada a un método con la sintaxis:

await miMetodoAsync();

De esta manera no se altera el flujo, ni hay que asignar métodos a eventos, aún más, ya no hay llamadas de retorno porque ahora el compilador se hace cargo de crearlas.

Task y Task<IResult>

El tipo devuelto de una función asíncrona debe ser void, Task o Task<T>. El tipo devuelto de una función anónima es el tipo del return (si hay alguno) del delegado.

En una función asíncrona con el tipo de retorno void o Task, las sentencias return no deben tener una expresión.

Cuando el tipo de retorno es Task<T> las sentencias return deben tener una expresión que sea implícitamente convertible a T.

async

De manera convencional los métodos asíncronos usan el sufijo Async para indicar que su ejecución se puede llevar a cabo después de que incluso el método que haga la llamada ya haya terminado.

Un método async ofrece una forma muy conveniente de hacer cosas que tardan mucho tiempo sin provocar bloqueos en el hilo que hace la llamada. El hilo que hace la llamada a un método async puede continuar sin tener que esperar a que el método async termine.

await

Una expression await solo se permite cuando ocurre dentro de un método asíncrono.

Comunmente, un método modificado por el modificador async contiene por lo menos una sentencia await. Tal método corre de forma síncrona hasta que se encuentra con la primera expresión await, momento en el cual la ejecución se suspende hasta que la tarea esperada se complete.

Elementos necesarios para usar Async

Async está disponible en la versión Beta de Visual Studio 11 o como una descarga CTP (Community Technology Preview) para Visual Studio 2010 SP1.

Ejemplo usando async y await

Como un pequeño ejemplo para comprender como es posible utilizar async y await generemos un pequeño proyecto WPF que nos permita ver el efecto del patrón TAP

Primer ejercicio: Creando la aplicación síncrona

Tarea 1 - Creación de una aplicación síncrona

1. Inicie Visual Studio 11 y creé una nueva aplicación WPF en C# llamada EjemploAsyn.

2. Cambie las propiedades de la ventana principal para que tenga un tamaño de 480 por 480 pixeles.

3. Agregue dos botones y un ListBox. Asigne a los botones los nombres BotonLeer y BotonMensaje respectivamente. Al ListBox asigne el nombre de ListaDeArchivos.

4. Acomode los componentes de manera que tengan el siguiente aspecto:



5. Abra el archivo de código en C# asociado a MainWindow MainWindox.xaml.cs y agregue el siguiente método justo debajo del constructor.

 

private IEnumerable<string> ObtenerArchivos()

{

    var archivos = from archivo

    in

    System.IO.Directory.GetFiles(@"C:\Windows\System32")

    select archivo;

    System.Threading.Thread.Sleep(5000);

    return archivos;

}

6. Haga doble clic sobre el botón BotonLeer para generar el manejador del evento Click y agregue el siguiente código.

private void BotonLeer_Click(object sender, RoutedEventArgs e)

{

    BotonLeer.IsEnabled = false;

    ListaDeArchivos.ItemsSource = ObtenerArchivos();

    BotonLeer.IsEnabled = true;

}

7. Ahora regrese al modo diseño y haga doble clic sobre BotonMensaje para generar el manejador del evento Click. Enseguida, agregue el siguiente código al método generado.

private void BotonMensaje_Click(object sender, RoutedEventArgs e)

{

    MessageBox.Show("Son las : " +

    DateTime.Now.ToLongTimeString());

}

8. Haga funcionar la aplicación y presione el botón Leer datos. Observe que la aplicación se congela y no es posible presionar el botón Mensaje. Luego de 5 segundos se llena el ListBox con los archivos del directorio y el botón Mensaje ya es funcional y muestra el mensaje.



Segundo ejercicio: Creando la aplicación asíncrona

Tarea 1 - Modificación del método ObtenerArchivos para que sea asíncrono.

1. Vaya al contenido del método ObtenerArchivos y modifique su estructura de manera que el tipo de dato que devuelva cambie de IEnumerable<String> a Task<IEnumerable<String>> y el nombre del método tenga ahora el sufijo “Async” como se muestra.

private Task<IEnumerable<String>> ObtenerArchivosAsync()

2. Ahora envuelva el código del método para que devuelva un objeto de tipo Task.

private Task<IEnumerable<String>> ObtenerArchivosAsync()

{

    return Task.Run(() =>

        {

        System.Threading.Thread.Sleep(5000);

        var archivos = from archivo in

            System.IO.Directory.GetFiles(@"C:\Windows\System32")

            select archivo;

        return archivos;

        });

}

Tarea 2 – Modificación del manejador del evento Click de BotonLeer para que sea capaz de hacer llamadas asíncronas.

1. Cambie la estructura del método BotonLeer_Click agregando el modificador async como se muestra.

private async void BotonLeer_Click(object sender, RoutedEventArgs e)

Observe que ahora el método tiene el modificador async antes del modificador de tipo void.

2. Ahora modifique la llamada al método ObtenerArchivos para que se haga a través de una llamada asíncrona usando la palabra reservada await como elemento modificador de la llamada al método. Recuerde que hemos cambiado ya el nombre del método agregando el sufijo Asycn.

ListaDeArchivos.ItemsSource = await ObtenerArchivosAsync();

3. Haga funcionar la aplicación, presione el botón Leer datos y compruebe que la aplicación no está congelada y es receptiva y que ahora si es posible presionar el botón Mensaje sin tener que esperar que termine el lapso de 5 segundos.


En este segundo ejercicio hemos creado una aplicación que no congela su funcionamiento por haber iniciado una llamada a un método.

 

DEMOSTRACIÓN

En Visual Studio vamos a dar click en menú File à New à Project


En la Ventana emergente le damos click a Window, seleccionamos la opción “Console Application” y espacio Name colocamos el nombre del proyecto que para el Ejemplo es “Demo 10 20483” y luego presionamos el botón OK


En el editor de código arriba del método Main() vamos a crear una clase denominada ‘Pizza’



Luego crearemos otra clase denominada ‘Pizzeria’


Debajo del método Main() procederemos a codificar los procedimientos que realizará acciones de modo Asíncrono.





En el método Main() mandamos a ejecutarlas


Ejecutamos


Y el resultado es el siguiente:






Tal vez te interesen estas entradas

No hay comentarios