Luis Guerrero Hablando de .NET, Silverlight, WPF, Windows Phone 7 y depuración

17Jul/100

Material de la formacion de Microsoft Surface [Video]

El 28 de junio se impartió una formación de Surface en Microsoft España, fueron 6 horas en las que repasamos los conceptos fundamentales del desarrollo de Surface en XNA y sobre todo en WPF.

Aquí tenéis el material de la charla, la presentación y la grabación del video (son unas 4~5 horas y 1.3GB).

image

Install Microsoft Silverlight

Que lo disfrutéis.

Luis Guerrero.

Tagged as: , , , No Comments
9Apr/100

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.

4Mar/100

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/

Filed under: .Net, Cocurrencia, MEF No Comments
29Nov/090

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.

Filed under: .Net, Cocurrencia No Comments
13Nov/090

Silverlight, un mejor manejo de los servicios

Como todos es sabido Silverlight trae soporte para invocar servicios web, tanto servicios web tradicionales de .net como servicios de WCF. En esto últimos solo con soporte para httpBasicBinding.

Cada vez que generamos un proxy en Visual Studio para un proyecto de Silverlight, el proxy generado solo soporta invocaciones asíncronas. No podemos de ninguna manera hacer una invocación síncrona a un servicio web y esperar a la respuesta. Puede haber muchas maneras por las cuales Microsoft implemento este comportamiento predeterminado, pero creo que el más importante de todos es hacer que la UI de las aplicaciones de Silverlight *nunca* dejen de responder.

Así que puestos en antecedentes, podemos ahora estudiar nuestro problema e intentar mitigarlo. Cuando generamos un proxy en Visual Studio, lo que obtenemos es una función con el mismo nombre que la operación del servicio + “Async” y un evento que es el nombre de la operación + “Completed” en la que en los argumentos de respuesta tenemos el resultado de la invocación del servicio.

Algo como esto:

public partial class TraditionalServices : UserControl
{
    private ServiceClient service;
    public TraditionalServices()
    {
        InitializeComponent();

        service = new ServiceClient();
        service.GetDateCompleted += new EventHandler<GetDateCompletedEventArgs>(OnGetDateCompleted);
        service.GetEmployeeCompleted += new EventHandler<GetEmployeeCompletedEventArgs>(OnGetEmployeeCompleted);

        Loaded += new RoutedEventHandler(OnLoaded);
    }

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        service.GetDateAsync();
    }

    void OnGetEmployeeCompleted(object sender, GetEmployeeCompletedEventArgs e)
    {

    }

    void OnGetDateCompleted(object sender, GetDateCompletedEventArgs e)
    {

    }
}

Conforme uno empieza a trabajar con los servicios de Silverlight encuentra que el código se puede volver un poco complicado puesto que no podemos invocar al servicio y después trabajar directamente con el resultado sino que lo tenemos que hacer en el método que se llamará cuando se termine la invocación del servicio.

Lo que os propongo en este artículo es que construyáis una clase Helper que os ayude a lidiar con estos problemas y hacer así el código un poco más claro.

Del código anterior para realizar la invocación a un servicio pasamos a esta:

service.GetDateTime(value =>
{
    string currentDateTime = value.ToString();
});

Como se puede apreciar el resultado es mucho mejor que la manera tradicional de trabajar con los proxies además de que el código queda mucho más claro.

¿Cómo está este helper implementado?

La idea es usar expresiones Lambda para hacer el código más legible, lo único que necesitamos es un delegado de tipo Action<T> en el que T será del mismo tipo del resultado de nuestra invocación al servicio web.

public void GetDateTime(Action<DateTime> value)
{
    service.GetDateAsync(value);
}

Con este simple patrón podemos simplificar las llamadas al servicio web y esconder su complejidad.

public partial class MainPage : UserControl
{
Helpers.ServiceHelper service;
public MainPage()
{
   InitializeComponent();

   service = Helpers.ServiceHelper.Instance;

   service.GetDateTime(value =>
   {
       string currentDateTime = value.ToString();
   });

   service.GetEmployee(value =>
   {
       ListBox listbox = new ListBox();
       listbox.ItemsSource = value;
       LayoutRoot.Children.Add(listbox);
   });

   service.DoStuff(() =>
   {
       // do stuff done
   });
}
}

Lo que hace la clase Helper es, cada vez que se realiza una invocación del servicio web se pasa por parámetro una referencia del delegado de tipo Action<T> que contiene la función que se llamará cuando termine la invocación. Una vez que termina la invocación del servicio lo que hacemos es obtener ese valor de vuelta y invocar al delegado con el resultado que es del mismo tipo que la signatura del delegado Action<T>.

public class ServiceHelper
{
private static ServiceHelper instance = new ServiceHelper();
public static ServiceHelper Instance { get { return instance; } }

private ServiceClient service;

private ServiceHelper()
{
   service = new ServiceClient();
   service.GetDateCompleted += new EventHandler<GetDateCompletedEventArgs>(OnGetDateCompleted);
   service.GetEmployeeCompleted += new EventHandler<GetEmployeeCompletedEventArgs>(OnGetEmployeeCompleted);
   service.AddCompleted += new EventHandler<AddCompletedEventArgs>(OnAddCompleted);
   service.DoStuffCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(OnDoStuffCompleted);
}

void OnDoStuffCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
   if (e.Error == null)
   {
       Action action = (Action)e.UserState;
       action();
   }
}

void OnAddCompleted(object sender, AddCompletedEventArgs e)
{
   if (e.Error == null)
   {
       Action<int> action = (Action<int>)e.UserState;
       action(e.Result);
   }
}

void OnGetEmployeeCompleted(object sender, GetEmployeeCompletedEventArgs e)
{
   if (e.Error == null)
   {
       Action<ObservableCollection<Employee>> action = (Action<ObservableCollection<Employee>>)e.UserState;
       action(e.Result);
   }
}

void OnGetDateCompleted(object sender, GetDateCompletedEventArgs e)
{
   if (e.Error == null)
   {
       Action<DateTime> action = (Action<DateTime>)e.UserState;
       action(e.Result);
   }
}

public void GetDateTime(Action<DateTime> value)
{
   service.GetDateAsync(value);
}

public void GetEmployee(Action<ObservableCollection<Employee>> value)
{
   service.GetEmployeeAsync(value);
}

public void Add(AddArguments args, Action<int> value)
{
   service.AddAsync(args.Operand1, args.Operand2, value);
}

public void DoStuff(Action value)
{
   service.DoStuffAsync(value);
}

public class AddArguments
{
   public int Operand1 { get; set; }
   public int Operand2 { get; set; }
}
}

Os podeis descargar de aquí el ejemplo completo. http://www.luisguerrero.net/downloads/servicehelper.zip

Saludos. Luis.

Filed under: .Net, Silverlight No Comments
13Sep/090

TPL – Cancelacion de Task

¡Hola a todos! Seguimos con los post sobre Task Parallel Library de .NET Framework 4, en este artículo vamos a ver cuál es el soporte de cancelación de Task que tenemos en TPL.

Como hemos comentado en el artículo anterior las Task son la unidad mínima de ejecución de TPL, incluso PLINQ (Parallel LINQ) utiliza Task internamente para sus operaciones. También hemos visto como las Task tienen alguna similitud con los Worker Threads del ThreadPool de .NET.

Cuando nosotros en código lanzamos un Worker Thread con el método ThreadPool.QueueWorkItem, estamos encolando un trabajo para que se ejecute en otro Thread diferente, pero no tenemos control en como este Worker thread se ejecuta, de hecho no podemos saber cuándo se ha completado, no podemos cancelarlo y no podemos devolver un resultado de esa ejecución asíncrona.

Esto ahora con las Task cambia, ahora a través de la propiedad Status podemos saber en qué estado está nuestra Task, la propiedad Result nos dará el resultado de la ejecución de la Task. Pero, ¿Qué hay de la cancelación?.

Cancelar un Task no es una tarea trivial, porque implica muchas decisiones y puede conllevar muchos errores. Si pensamos en cómo se cancela un Thread, el CLR lo que hace es inyectar un ThreadAbortException en la ejecución del thread haciendo que este se aborte, pero lo que no podemos controlar es en qué punto de la ejecución del thread se va a producir esto, y lo más peligroso de eso es que podemos estar dentro de un bloque de lock y la inyectarse la excepción puede pasar que nunca se salga de ese bloque de lock, haciendo que pueda pasar un deadlock en nuestro código. Este es solo un ejemplo de lo que puede pasar pero por supuesto puede ser mucho más complicado.

¿Cómo se puede cancelar una Tarea de manera segura?

Hay dos opciones posibles, si la tarea esta creada y se ha llamado al método Start y la Task está esperando para ejecutarse (Status=WaitToRun) y se cancela TPL automáticamente cancelará la tarea por nosotros (Status=Cancelled). Pero si la tarea está ejecutándose o esperando a un evento externo se realiza de otra manera.

Para poder ver esta segunda parte tenemos que comprender primero como se gestiona esto en código para entender cuál es el mecanismo que TPL nos proporciona para cancelar Task.

Task t = new Task((index) =>
{
    Thread.SpinWait(1000);
    if (!cancellationSource.IsCancellationRequested)
    {
        Thread.Sleep(r.Next(0, 1000));
    }
}, i, cancellationSource.Token);
list.Add(t);

Si nos fijamos en este ejemplo de código al crear una instancia de la clase Task ahora pasamos por parámetro un CancellationToken que nos va a permitir comunicarnos con el sistema de cancelación de TPL. Ese CancellationToken viene de una estructura llamada CancellationTokenSource que es realmente la que gestiona la comunicación de la cancelación de las Task.

Lo primero que hacemos es generar una lista con todas las Task que vamos a ejecutar, con eso lo que tenemos es instancias de la clase Task, pero todavía no se están ejecutando, es después cuando llamamos al método Start de todos los objetos Task a la vez.

Como el TaskScheduler predeterminado es el ThreadPool de .NET al principio en una carga de trabajo tan grande 10000 Task, el ThreadPool se tendrá que tunear a sí mismo para empezar a crear Workers Threads y aumentar dinámicamente la capacidad de ejecución por nosotros. Esta es una de las cosas más cómodas de TPL, porque nosotros no tememos que directamente estar pendiente de la heurística del ThreadPool para saber cuál es el número de Threads ideal para nuestro sistema.

Además de todo esto tenemos un método que nos permite cancelar todas las Task a la vez.

public void CancelTask()
{
    cancellationSource.Cancel();
}

Simplemente lo que hacemos es llamar a Cancel del objeto CancellationTokenRequest y este se comunicará con la infraestructura de TPL para empezar la cancelación. Como dijimos antes la cancelación de tareas que están es estado WaitingToRun es automática, pero las que se están ejecutando es más complicado.

Si nos fijamos en el ejemplo de arriba, en el cuerpo del método que se ejecutará por cada Task, hay una sentencia condicional if !cancellationSource.IsCancellationRequested en la que estamos comprobando que no se ha realizado una solicitud de cancelación de tareas. Esto es así porque es la única manera segura y organizada de cancelar un Task. Este ejemplo no es muy representativo para el soporte de cancelación, pero por ejemplo si en esta Task se estuvieran generando por pasos un informe que tarda mucho tiempo, generar el reporte, consulta a la base de datos, ect, podemos hacer comprobaciones en cada paso de que se ha solicitado una cancelación de la Task y así de manera segura cancelar la petición y liberar todos los recursos generados por ese reporte.

Para poder sacar todo el partido de la cancelación en nuestras Task, tenemos que trabajar activamente con TPL para que la experiencia de cancelación sea la más adecuada a cada situación, habrá pasos que no se puedan cancelar hasta un determinado punto, en cualquier caso TPL nunca abortará la ejecución de ese Task por nosotros, pues como he comentado antes esto puede conllevar muchos problemas.

image

Otro de los escenarios posibles cuando se trabaja con cancelación es que de alguna manera nos gustaría saber cuándo un CancellationToken se ha cancelado, para eso tenemos varias opciones, porque el propio CancellationToken tiene un método para que registremos un delegado de tipo Action que será llamado cuando se cancele el CancellationToken. También existe la opción de registrar un objeto de tipo ICancelableOperation, que es la interfaz que implementan el tipo CancellationTokenSource para poder enlazar así objetos de cancelación y crear dependencias entre ellos.

Aquí os podéis descargar el código de ejemplo de la aplicación de WPF.

http://www.luisguerrero.net/downloads/TaskCancel.zip

Saludos. Luis.

Filed under: .Net, Rendimiento, TPL No Comments
6Sep/090

Task Parallel Library – Introduccion

Una de las nuevas novedades que .NET Framework 4.0 incluye es el la Task Parallel Library una serie de APIS nuevas para la programación multihilo. La idea principal de esta librería, que viene incluida en el propio framework, es que cuando tengamos que añadir paralelismo y concurrencia a nuestras aplicaciones sea de lo más sencillo.

Actualmente los procesadores ya no incrementan la velocidad en Gigahercios sino que lo que hacen es replicar el hardware haciendo que nos encontremos dentro del mismo encapsulado FPGA dos procesadores exactamente iguales con sus caches de segundo y primer nivel. Esto cambia la manera de desarrollar software porque ya no nos encontramos con procesadores más rápidos sino con procesadores con más cores, 2,4,6,8 ect.

Con este nuevo escenario tenemos los desarrolladores tenemos que empezar a paralelizar nuestro software para explotar toda la potencia de los procesadores.

Una de las cosas buenas de la TPL, es que si la maquina donde se va a ejecutar tiene 2, 4 o 8 procesadores, la TPL es capaz de escalar sin necesidad de recompilar ni configurar, es decir es capaz de usar todos los cores disponibles.

Eso quiere decir que cuanto más cores utilicemos más velocidad ganaremos, aunque esto no es siempre así, porque no todas las tareas son sensibles de ser paralelizadas. Además hay que tener en cuenta que usar la TPL añade complejidad en la ejecución de la aplicación y esto en algunas ocasiones puede hacer que se degrade el rendimiento y no lo aumente. Hablaremos de eso más adelante.

Aquí tenemos la primera toma de contacto con la TPL:

Parallel.For(startIndex, endIndex, (currentIndex) => DoSomeWork(currentIndex));

Parallel.For nos permite ejecutar de manera concurrente el cuerpo de un bucle for, haciendo que la ejecución se propague por todos los cores disponibles en el sistema. Así de sencillo.

Pero como hemos comentado antes no esto a veces aumenta el rendimiento y en otros lo degrada. Veamos porque.

Cuando realizamos un bucle normal todo el código se ejecuta de manera secuencial, es decir una instrucción detrás de otra, pero cuando estamos realizando una paralelizacion de nuestro código tenemos varios threads que están ejecutando código en el mismo instante de tiempo. Si nos ponemos a pensar cómo se podría implementar a mano un Parallel.For, lo primero que tendríamos que hacer es realizar una partición de las iteraciones para dependiendo de los procesadores que tengamos repartir el trabajo.

Si tenemos por ejemplo que recorrer una lista de 50000 elementos y tenemos 2 procesadores, podemos partir la lista de dos sublistas de 25000 y generar dos threas que se encarguen de recorrer esos elementos. Ponemos los threads a ejecutar y tenemos que sincronizar cuando los dos threads terminan.

Básicamente esto es de lo que se encarga el Parallel.For de hacer por nosotros, de una manera cómoda y elegante.

Ahora bien, ¿Cuándo no es recomendable realizar un Parallel.For?, hay una regla que funciona en la mayoría de los casos, cuando el tiempo de ejecución del cuerpo del for sea mayor o igual que el tiempo de creación de los threas y de la sincronización, también es lo mismo si tenemos colecciones pequeñas. ¿Qué quieres decir esto?, veamos un ejemplo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ParalleFor
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program();
        }

        private List<int> GetRandomList()
        {
            List<int> list = new List<int>();
            for (int i = 0; i < 90000000; i++)
            {
                list.Add(i);
            }
            return list;
        }

        public Program()
        {
            List<int> list = GetRandomList();

            Stopwatch st = new Stopwatch();

            // sum all
            decimal value = 2;
            st.Start();
            for (int i = 0; i < list.Count; i++)
            {
                decimal final = value * list[i];
            }
            st.Stop();
            Console.WriteLine(st.Elapsed);
            st.Reset();

            st.Start();
            Parallel.For(0, list.Count, index =>
            {
                decimal final = value * list[(int)index];
            });
            st.Stop();
            Console.WriteLine(st.Elapsed);
        }
    }
}

Si nos fijamos la lista de con la que trabajamos es realmente grande, eso significa que si paralelizamos el bucle for ganaremos en rendimiento como muestra la salida de la ejecución. Pero si tenemos una lista pequeña no ganaremos tiempo sino que perderemos porque tenemos que sincronizar los n threas para esperar a que todos terminen, además del tiempo necesario para inicializarlos.

Otro de los grandes problemas de la paralelizacion es que necesitamos estructuras para sincronizar nuestro código y tener claro los conceptos de: locks, deadlocks, race condition (data and flow), etc.

En el siguiente artículo veremos el soporte para Task, las unidades básicas de ejecución dentro de TPL.

Aquí tenéis el código fuente del ejemplo.

http://www.luisguerrero.net/downloads/parallefor.zip

 

Saludos. Luis.

Filed under: .Net, Rendimiento, TPL No Comments
23Jun/090

Tool: Memory Pressure

Esta sencilla herramienta permite generar presión en la memoria del sistema a nuestro gusto.

clip_image002

La interfaz de usuario es muy sencilla, podemos seleccionar la cantidad de Megabytes que queremos reservar y cuál es el tamaño de los bloques que queremos usar. Hay que tener en cuenta que esta aplicación utiliza la reserva de memoria del heap de Windows, es decir llama a Marshal.AllocHGlobal que a su vez llama a LocalAlloc.

Una vez que tenemos la memoria reservada podemos liberarla para poder eliminar la presión.

Durante la reserva de memoria se llama a GC.AddMemoryPressure que notifica al recolector de basura la presión actual que se está haciendo en memoria nativa.

Os podeis instalar este software desde: http://www.luisguerrero.net/applications/MemoryPressure/

Tambien os podeis descargar el código fuente: http://www.luisguerrero.net/downloads/MemoryPressure.zip

Luis.

Filed under: .Net, Rendimiento No Comments
15Jun/090

Constructores y Finalizadores

Dentro de la orientación a objetos nos encontramos dos tipos de métodos especiales, el constructor y el destructor. En .NET hay dos tipos de constructores de instancia (ctor) y de tipo (cctor) también llamado constructor estático.

Constructores

Cuando un tipo es accedido por primera vez, se ejecuta el constructor estático bajo un doble lock (Como implementar un Singleton concurrente) para asegurar que solamente se llama una vez, si además se está creando una instancia del objeto se llamará al constructor del objeto para inicializarlo. También se llama a todos los constructores base hasta que se llega a System.Object.

Hay que tener en cuenta que el constructor de un objeto no es más que un método que puede aceptar parámetros y que devuelve una referencia sí mismo a this. Como programadores no tenemos que manejar esta situación puesto que el propio compilador la realiza por nosotros.

Hay un caso excepcional en el que podemos crear un objeto pero no obtener una referencia a el nunca, si en el constructor se lanza una excepción. En este caso, el objeto se inicializa, se llama a los constructores base y se aborta el método en el punto en el que se lance la excepción, pero ya se ha reservado memoria para el objeto y nunca podremos acceder a esa referencia de ese objeto a medio construir.

public class Foo
{
    public DateTime DateTime { get; set; }
    public string file { get; set; }
    public Foo()
    {
        DateTime = DateTime.Now;
        string[] v = file.Split(',');
    }
}

Aquí tenemos un ejemplo de una clase que en el constructor lanzará una excepción de tipo NullReferenceException, realmente si se ha creado el objeto solo que si hacemos algo como:

Foo f = new Foo();

Nunca llegaremos a obtener la referencia del objeto hay creado y además tenemos que tener en cuenta que se tendrá que recolectar el objeto para liberar memoria en la siguiente recolección de basura.

Es por eso que hay que tener mucho cuidado con lo que se pone en el constructor porque podemos dejar a nuestro tipo inutilizado.

La situación se agrava si se lanza una excepción en el constructor de tipo, ya que no podremos acceder a ninguna variable estática ni crear instancias de este tipo.

Destructores o finalizadores

Los destructores (o finalizadores) son los métodos que se llamarán cuando el objeto ya no es usado y se reclama la memoria usada. En este caso es el CLR el que se encarga de llamar a este finalizador pues nosotros no tenemos ningún mecanismo para liberar un objeto.

Un finalizador se define de esta manera:

~Foo()
{
   Console.WriteLine("Adiossss !!");
}

Eso significa que cuando esa instancia del tipo Foo sea recolectada se ejecutará este método. Si miramos al IL generado por este programa realmente el destructor ha pasado a llamarse Finalize() y está marcado como virtual.

Además de definir un destructor de clase hay otro mecanismo para poder definir un destructor, implementando la interfaz IDisposable. Este es el único mecanismo que tiene un programador de .NET para poder definir un destructor de objeto y además poder llamarlo el mismo de codigo de usuario.

Para evitar que este método sea llamado otra vez por el CLR existe el método GC.SupressFinalize.

¿Cómo es llamado este método?

Cada vez que se realiza una recolección de basura el GC examina todos los objetos y si encuentra alguno que es finalizable, es decir, tiene destructor o implementa IDisposable, entonces ese objeto que está listo para ser recolectado pasa a la cola de finalización.

Cuando los objetos están en esa cola de finalización un Thread de alta prioridad se encarga de sacar un elemento de la cola, ejecutar su finalizador y marcarlo como listo para ser recolectado.

Consideraciones a tener en cuenta:

· Cuando el objeto está listo para ser finalizado se lleva a la cola de ReadyToFinalize y además todos los objeto de su grafo son marcados. Eso significa que si ese grafo de objeto normalmente moriría en esta recolección, ahora es promovida a la siguiente, simplemente porque su objeto raíz es finalizable.

· Las generaciones más viejas son recolectadas menos que las generaciones más jóvenes lo que indica que nuestro grafo de objetos puede permanecer vivo durante mucho tiempo hasta que es completamente finalizado y recolectado.

· Al utiliza un único thread, aunque está en prioridad alta, puede darse el caso de que el si tenemos una maquina con 32 procesadores y solamente tenemos una finalizado objetos la cola pueda crecer mucho.

· Hay que tener mucho cuidado con lo que se ejecuta en el finalizador porque si se produce una excepción el proceso entero se descarga. No estamos hablando de que se descargue el dominio de aplicación sino todo el proceso.

Garantías de finalización:

· Durante la ejecución normal de la aplicación y durante cada recolección de basura, se llamara a los finalizadores de los objetos que haya en la cola.

· Si el proceso termina sin la coordinación del CLR, llamando a TerminateProcess o ExitProcess, el CLR tendrá su primera noticia de que el proceso se está cerrando cuando se envíe el mensaje DLL_PROCESS_DETACH en el DllMain. Así que el CLR no tiene tiempo de hacer nada y lo único que puede pasar es que termine los finalizadores críticos (CriticalFinalizerObject).

· Si el proceso es cerrado con el pleno conocimiento del CLR, llamado a Exit o Enviroment.Exit, se finalizarán los objetos que están en la cola de finalización y los finalizadores críticos. Pero los posibles objetos que salgan de una recolección de basura listos para ser finalizados se quedarán sin ser finalizados.

· Si se descarga el dominio de aplicación entonces solamente se finalizarán los objetos que estuvieran en la cola de finalización y los finalizadores criticos.

El codigo del ejemplo: http://www.luisguerrero.net/downloads/ctor.zip

Saludos. Luis.

1Jun/090

Rendimiento para el modelado de clases

Rendimiento. En muchos proyectos en los que trabajo una de las preocupaciones a la hora de hacer el proyecto es el rendimiento de la aplicación

Una de las tareas, por no decir la única, es trabajar con datos en una aplicación, modelamos constantemente clases que tiene estado y a su vez exponen una serie de métodos para que los podamos invocar. Hoy a lo que me voy a dedicar a explicar es justamente a ese modelado de datos, al estado de nuestras clases.

Dentro de .NET Framework tenemos varias maneras de definir el estado de una clase:

  • Field (Campo)
  • Property (Propiedad)
  • DependencyProperty (Propiedades de Dependencia)

Estas últimas están pensadas para la interacción de esas clases con Interfaz de Usuario (UI).

Las propiedades son una normalización de los métodos de acceso (set) o de obtención (get) que normalmente se hacía para obtener el acceso a los campos o modificarlos. Realmente las variables se guardan en los campos (field) solo que las propiedades permiten normalizar el acceso y encapsular su funcionalidad de acceso. Son implementadas como métodos dentro del ensamblado.

Lo que vamos a ver en este post es cual la velocidad de acceso a estas propiedades desde .net para saber cuál es la mejor opción si estamos trabajando con el estado de las propiedades y campos. Cualquiera me podría decir que según la lista anterior está claro que siempre la mejor opción (desde el punto de vista del rendimiento) son los campos (Field) puesto que accederos directamente y sin intermediarios, pero además de eso cuando los proyectos empiezan a complicarse puede pensar en usar la reflexión para acceder a los datos, porque se quiere automatizar el acceso a las propiedades de las clases.

Así que lo que vamos a hacer es tener dos tipos de clases una con campos y propiedades, (Field y Property), otra con DependencyProperty y vamos a medir el tiempo que tardamos en acceder a esas variables. Una de las desventajas de usar DP es que para poder usar su funcionalidad tenemos que heredar de la clase DependencyObject, que es la clase que implementa la funcionalidad de DP. Además como he comentado anteriormente las DP únicamente se usar para definir las propiedades de los controles de interfaz de usuario y de los objetos de negocio que interactúan con la UI.

Lo que vamos a hacer son una serie de pruebas con una clase intermedia para medir el tiempo y que se encargue de ejecutar el bloque de código n veces y de medir el tiempo que tarda en hacerlo.

Para la medida del tiempo no vamos a usar DateTime.Now antes de empezar y después de ejecutar porque la medida de tiempo de DateTime.Now no es de alta resolución y no vamos a tener la precisión que necesitamos para medir diferencias de tiempo. En vez de DateTime.Now vamos a usar Stopwatch, clase que está en System.Diagnosis que nos permite hacer medidas de tiempo en alta resolución, el uso de esta clase es bastante sencilla así que el lector la podrá descubrir por el mismo.

Vamos al lio, tenemos está clase normal de C#

public class NormalType
{
    internal int number;

    public int Number
    {
        get { return number; }
        set { number = value; }
    }

    internal string _string;

    public string String
    {
        get { return _string; }
        set { _string = value; }
    }
    internal Item item;

    public Item Item
    {
        get { return item; }
        set { item = value; }
    }
}

Como podéis ver es una clase con tres propiedades un entero, un string y un tipo referencia complejo (Item), todas las propiedades tienen un campo que respalda el valor, así que realmente las propiedades simplemente exponen los valores de los campos sin más.

public class DependencyPropertyType : DependencyObject
{
    public int Number
    {
        get { return (int)GetValue(NumberProperty); }
        set { SetValue(NumberProperty, value); }
    }

    public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register("Number", typeof(int), typeof(DependencyPropertyType), new PropertyMetadata(0));

    public string String
    {
        get { return (string)GetValue(StringProperty); }
        set { SetValue(StringProperty, value); }
    }

    public static readonly DependencyProperty StringProperty =
        DependencyProperty.Register("String", typeof(string), typeof(DependencyPropertyType), new PropertyMetadata(null));

    public Item Item
    {
        get { return (Item)GetValue(ItemProperty); }
        set { SetValue(ItemProperty, value); }
    }

    public static readonly DependencyProperty ItemProperty =
        DependencyProperty.Register("Item", typeof(Item), typeof(DependencyPropertyType), new PropertyMetadata(null));

}

Esta otra clase es la clase que implementa las DependencyProperty, como veis ahora por cada propiedad hay una definición de una clase de tipo DependencyProperty que es estático y de solo lectura (static readonly) y además no es el tipo que definimos las propiedades. Eso que significa que los valores de esta clase son compartidos, desde luego no porque las propiedades son de instancia no estáticas, solo que ahora utilizamos dos métodos helpers que nos ayudan a acceder y establecer los valores de las propiedades (GetValue,SetValue). Esos dos métodos están definidos en la clase base DependencyObject. Realmente nosotros no tenemos información de donde se están guardando esas variables dentro de nuestra clase no hay ningún campo (Field) ni lista ni nada que nos indique donde se están almacenando esos valores, y si miramos en la clase base nos pasa lo mismo. En otro post desvelare toda la potencia y misterios de las DP ahora simplemente lo usaremos sin más para esta prueba de rendimiento.

Ahora lo que vamos a hacer son las pruebas en sí de acceso a estos valores.

image 

Sin reflexion

Con Reflexion

Getter Field

92,176

4483,588

Getter Property

142,813

3169,277

Getter Dependency Property

755,433

1619,854

Setter Field

0,607

3716,121

Setter Property

0,584

2600,364

Setter Dependency Property

129,623

973,799

La prueba está dividida en dos grandes grupos Setters y Getters (establecer y obtener).

Para los Setters (establecer) los campos tiene el mejor rendimiento cuando se trabaja con ellos, pero son los que tiene el peor rendimiento cuando se trata de acceder a través de reflexión, las propiedades es el mismo caso solo que se mejora un poco el tiempo de acceso desde reflexión y para las Dependency Property están muy equilibradas en cuanto a tiempo de acceso con y sin reflexión.

En el caso de Getters (obtener) la historia se repite, los campos y propiedades son increíblemente rápidos, pero cuando se trabaja con ellos a través de reflexión se penaliza, las Dependency Property en relación con el Setter son más rápidas con y sin reflexión.

El caso especial de las Dependency Proeprty.

¿Por qué las Dependency Properties tiene mejores tiempos?, podríamos decir que la prueba esta adulterada, porque realmente siempre se utiliza los métodos GetValue y SetValue que DependencyObject nos proporciona para acceder a esos valores y ahí es donde está la sobrecarga pero hay que tener en cuenta que la reflexión usada en esta prueba es solo para acceder a las instancias de las DependencyProperty que son necesarias en las llamadas de GetValue y SetValue.

Por si sentís curiosidad los valores de las instancias de clases que heredan de DependencyObject se guardan en un campo interno de la clase DependencyObject llamado _effectiveValues de tipo EffectiveValueEntry,

private EffectiveValueEntry[] _effectiveValues;

EffectiveValueEntry es la clase que manera el valor de una Dependency Property, cada una de estos EffectiveValueEntry tiene asociado un índice dentro de todos los registros de Dependency Proeprty al cual nosotros podemos acceder desde DependencyProperty.GlobalIndex (int) pero no podemos usar de ninguna manera, no sé porque Microsoft ha permitido acceder a esta propiedad si no tiene utilizad.

La solución de Visual Studio para que hagáis vuestras pruebas.

http://www.luisguerrero.net/downloads/DPPerformance.zip

Luis Guerrero.

Filed under: .Net, Rendimiento No Comments