Lanzamiento de Visual Studio 2010 – La importancia de la concurrencia

Hola a todos!

Dentro de poco empieza la gira de lanzamiento de Visual Studio 2010 por España y en este Lanzamiento tendré el honor de participar con una charla sobre la importancia de la computación paralela, así que espero veros a todos el día 13 de Abril en Barcelona y el 20 de Abril en Madrid.

Mientras podéis ir echando un vistazo al material sobre concurrencia de una charla anterior aquí.

Saludos!

Luis Guerrero.

Concurrent programming and Managed Extensibilty Framework

Este últimos mes he estado dando un par de charlas sobre programación concurrente en .NET Framework con Task Parallel Library y MEF (Managed Extensibility Framework) Framework de extensibilidad administrada, así que aquí tenéis todos los recursos, la presentación y las demos.

image

Task Parallel Lirarty demos in Visual Studio 2010 RC format

No hay demos de MEF pero te puedes bajar algunas de aquí http://www.codeplex.com/mef/

[Artalde.NET] Extensibilidad con MEF y paralelismo con TPL y PLINQ.

El próximo 3 de febrero, miércoles, tendrá lugar la siguiente charla del grupo de usuarios Artalde, esta vez hablando de algunas de las novedades de .NET Framework 4.0 para desarrolladores; una introducción a extensibilidad con MEF y paralelismo con TPL y PLINQ.

El lugar y hora, el de siempre; en la Universidad de Deusto, de 19:00 a 21:00 horas. El registro aquí.

En esta ocasión, será Luis Guerrero el que haga los honores y nos muestre las maravillas que nos trae la versión 4.0 del Framework…cremita de la buena!

Aquí os dejo la descripción completa de la charla:

En esta charlas veremos las novedades de las nos nuevas librerías que Microsoft incluye en .NET Framework para el desarrollo de extensibilidad de las aplicaciones, usado internamente por Microsoft para la extensibilidad de plug-ins en Visual Studio 2010, y cómo afrontar los problemas de concurrencia con Task Parallel Library.

MEF (Managed Extensibility Framework): El Framework de Extensibilidad para componentes administrados es una nueva librería incluida en el .NET Framework 4.0 que permite reutilizar aplicaciones y  componentes. Usando MEF, las aplicaciones .NET pueden avanzar de ser estáticamente compiladas a ser dinámicamente compuestas en runtime. Una aplicación MEF está compuesta de Parts que se exportan, se importan y se componen. http://www.codeplex.com/mef/

Parallel Programming in the .NET Framework: Son una serie de nuevas APIs que permiten al desarrollador trabajar con el software y paralelizar los componentes para sacar el máximo partido a toda la potencia que los procesadores de varios cores ofrecen. Veremos TPL (Task Parallel Library) que es la librería para trabajar con Task, que son las nuevas unidades mínimas de paralización (nunca más threads), también veremos PLINQ que nos ofrece que la posibilidad de ejecutar nuestras consultas de LINQ tradicionales en varios cores y con mínimo impacto en la modificación de nuestra query y para finalizar veremos las nuestras estructuras de datos para la programación paralela, como pilas, colas y listas.

Lugar:
Universidad de Deusto
Edificio ESIDE, Aula de videoconferencia (2º piso)
Avda Universidades, 24
48007, BILBAO

Escribiendo codigo concurrente de alto rendimiento con monitores

Las aplicaciones multi hilo o concurrentes van a ser el siguiente gran problema para los desarrolladores, y tenemos que estar listos para este cambio tan grade. En el .NET Framework 4, Microsoft incluye una serie de nuevas APIs que ayudan al desarrollador en la creación de aplicaciones concurrentes. Eso no significa que tengamos que despreocuparnos del código concurrente sino que a partir de ahora va a ser más fácil hacerlo.

Actualmente estoy trabajando en una aplicación que hace un uso intensivo de la API de TPL. Básicamente la aplicación genera una serie de Task que administran la ejecución de una serie de reglas aplicadas a una Uri. Además de eso mantengo una lista con la colección de Task creadas por mi aplicación, para contabilizar cuantas están ejecutándose y una serie de estadísticas de velocidad de la aplicación.

Esto significa que tenemos una UI donde vamos mostrando los datos, creada en WPF 4 que necesita comunicarse con este código para obtener todas las tareas que se están ejecutando en ese momento. Teniendo en cuenta que estoy usando una simple List<Tast> para guardar la referencia de todas las tareas, necesito una manera de bloquear la lsita para añadir elementos a la lista, enumerar la lista y eliminar elementos. Pero queiro que este bloqueo dure lo menos posible para hacer que mi aplicación se ejecute lo más rápido posible y además quiero solo bloquear para las operaciones importantes añadir y eliminar tareas

Así que tengo dos operaciones importantes, crear una nueva tarea y añadirla a la lista, y cuando la tarea termina eliminar esa tarea del servidor, pero tengo que tener en cuenta que múltiples tareas pueden estar ejecutándose a la misma vez.

La creación de tareas es responsabilidad de un temporizador que está configurado para ejecutarse para Segundo y si el número de tareas es menor que el número de tareas mínimas genera más tareas y cada tarea creada la añade al sistema. Teniendo en cuenta que este temporizador es ejecutado cada segundo, necesito bloquear mi lista, hacer mi trabajo y después desbloquear. Teniendo en cuenta que el bloqueo para acceder a la lista puede ser mayor que el tiempo del temporizador porque otros threads pueden estar usando la lista necesito establecer un tiempo máximo de bloqueo porque si no lo que conseguiré será una clásico convoy de bloqueos en mi aplicación.

Teniendo en cuenta esto dentro del método de mi temporizador utilizo la nueva API de Monitor.TryEnter de .NET 4 que intenta, para un número de milisegundos, adquirir el bloqueo exclusivo y atómicamente establecer un valor que indica si el bloqueo se ha obtenido o no. En mi caso he establecido el temporizador en 400ms, porque en mi método hago más cosas que trabajar con esa lista.

bool taken = false;
try
{
    Monitor.TryEnter(task, 400, ref taken);
    if (taken)
    {
        if (!cancelationTokenSource.IsCancellationRequested)
        {
            var count = (from p in task
                         where p.Status == TaskStatus.Running || p.Status == TaskStatus.WaitingToRun
                         select p).Count();

        }
    }
}
finally
{
    if (taken)
    {
        Monitor.Exit(task);
    }
}

Como se puede observar en el código estoy llamando a la función de Monitor.TryEnter dentro de un bloque de try/catch, y en el bloque de finllay si el bloqueo se ha adquirido lo libero llamando a la función Monitor.Exit. Lo hago de esta manera para asegurarme que si durante la ejecución de mi código se lanza una excepción el código de finally siempre será ejecutado y el bloqueo liberado. Si no lo hiciese de esta manera podría causar que se nunca se liberase el bloqueo y tener un deadlock.

El otro escenario donde trabajo con la lista es para obtener el número de tareas ejecutándose, y hago lo mismo dentro de accesor get de una propiedad, pero esta vez lo tengo configurado a 250ms. Si el bloqueo se adquiere satisfactoriamente, lo que hago es copiar la lista en una lista nueva par después de manera segura trabajar sobre esa nueva lista.

public List<Task> Tasks
{
    get
    {
        bool taken = false;
        List<Task> list = null;
        try
        {
            Monitor.TryEnter(task, 250, ref taken);
            if (taken)
            {
                list = new List<Task>(task.ToArray());
            }
        }
        finally
        {
            if (taken)
            {
                Monitor.Exit(task);                         
            }
        }
        return list;
    }
}

Esta solución es simple y mantiene tu código con la tasa de contención más baja posible, pues no esperas infinitamente en todos los casos, solo en los más importantes.

A parte de esto podría haber hecho un wrapper de List<T> con ReaderWriterLockSlim para controlar las operaciones de lectura y escritura durante el bloqueo, pero ReaderWriterLockSlim está pensado para trabajar con varios lectores y solo un escritor y en mi aplicación tengo múltiples escritores y solo un lector.

Saludos.

Luis.