Reactive Extensions – TPL Dataflow

En la entrada anterior decíamos que los Reactive Extension emplean una secuencia de datos y que esta secuencia de datos pueden ser eventos.

Esta es una de las características de los Rx que más gusta! la posibilidad de combinar los eventos y su asincronía con el poder de LINQ, reduciendo la cantidad de código que debemos escribir y facilitándonos la mantenibilidad del mismo.

Para éste ejemplo usaremos un FileSystemWatcher que estará pendiente de la creación de archivos sobre uno de las carpetas del disco, pero solo los archivos que cumplan con cierta condición serán procesados por una red de de flujo de trabajo provista por la TPL Dataflow, ésta, en si, se basa en una serie de bloques que procesaran datos de múltiples orígenes en varios bloques (Bloques de acción, bloques de unión, bloques de transformación, bloques de buffer…) enlazados entre si a través del método  LinkTo() y devuelven un resultado de dicho proceso. Hablar sobre TDL da para una serie completa, así que nos quedaremos con esta definición por ahora.

Dejemos que sea el código quien termine de contar la historia.

    public partial class Form1 : Form
    {
        //Declaración del watcher
        private readonly FileSystemWatcher _watcher;

        public Form1()
        {
            InitializeComponent();
            //Inicialización del Watcher indicando el path e indicando que lance los eventos asociados
            _watcher = new FileSystemWatcher(@"D:\Test") { EnableRaisingEvents = true };
        }

        private void Form1Load(object sender, EventArgs e)
        {
            //Declaración de un bloque de transformación
            //Se basa en un Func, este recibirá un string y devolverá un Image.
            //El código que realizará dicha transformación esta en el método Transform(string path)
            var transformation = new TransformBlock((Func)Transform);

            //Declaración de un bloque de acción
            //Se basa en un Action, es decir que ejecutara el código del delegado 
            //y no retornará ningún valor, en este caso solo pintara en pantalla los Image que se le pasen
            //a traves de un control picturebox sobre un control TableLayoutPanel
            var action = new ActionBlock(img => tableLayoutPanel.Controls.Add(new PictureBox
                                                                                     {
                                                                                         Image = img,
                                                                                         Width = 50,
                                                                                         Height = 50,
                                                                                     }),

                //Los TDL no realizan procesamiento en paralelo de forma predeterminada
                //para esto es necesario indicarlo mediante uno de los DataflowBlockOptions
                //como es el ExecutionDataflowBlockOptions
                new ExecutionDataflowBlockOptions
                {
                    TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(), //Sincronización de contexto (violación de thread principal)
                    MaxDegreeOfParallelism = 5 // Numero de mensajes que se pueden procesar al mismo tiempo
                });

            //Enlazar el bloque de transformación con el bloque de acción
            transformation.LinkTo(action);

            //Inicializará una secuencia de eventos observables a partir del patrón de eventos de .NET
            //con una administración automática de "desuscripción" de eventos, dado que la subscripción 
            // a estas secuencias es un tipo de IDisposable
            var observable = Observable.FromEventPattern
                (
                    fsHandler => _watcher.Created += fsHandler,
                    fsHandler => _watcher.Created -= fsHandler)
                    //Consulta directa sobre los la secuencia observable de delegados
                    //a partir del eventargs (Nótese el patrón de eventos de .NET)
                    //En este caso todos los que empiecen por "a" serán mostrados en pantalla
                .Where(x => x.EventArgs.Name.ToLower().StartsWith("a"));
            //La suscripcion a esta secuencia observable invocara el bloque de transformación
            //que esta enlazado al bloque de acción
            observable.Subscribe(x => transformation.Post(x.EventArgs.FullPath));
        }

        //Crear un image a partir de su path
        private static Image Transform(string path)
        {
            Image image = Image.FromFile(path);
            return image;
        }
    }

Como vemos, es posible generar una secuencia observable de delegados de eventos que cumplan con el patrón descrito por los eventos de .NET, pero… y si nuestras clases no usan esto? si no usamos un EventHandler? ¿Hay operadores para trabajar con estos? este es el interrogante a resolver en el siguiente post.

Espero que les sea de utilidad.

Hasta el próximo post.

Anuncios
Reactive Extensions – TPL Dataflow

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