miércoles, 19 de septiembre de 2012

EL SDK Visualizador de Concurrencia: Técnicas Avanzadas de Visualización.

 

En el post anterior , pudimos verificar en diferentes escenarios el uso del visualizador de concurrencia, el dia de hoy quiero mostrarles unas técnicas mejoradas con el fin de obtener un mayo control sobre la dorma de visualizar los eventos mas significativos dentro de una aplicación.

Con el fin de ilustrar bien los comportamientos de la aplicación, voy a utilizar a manera de simulación aplicación simula el proceso que lleva a una persona del común ir al trabajo, Se simularan cambios de 4 procesos usando múltiples iteraciones (Cada Iteracion representa una hora en tiempo de simulación).

Para cada iteración la aplicación realiza los siguientes cuatro cálculos:

1. Levantarse.

2. Bañarse.

3. Desayunarse.

4. Salir.

En esta simulación se puede realizar en paralelo y usare C# y el Thread Poll para simular la carga de trabajo de paralelismo.

Sin explicar mucho el código a continuación presento el código con el cual trabajaremos:

static void Main(string[] args)

{

MarkerWriter miwriter =

new MarkerWriter(new Guid("9f34bddd-eae4-40c9-b668-91d78fc0b326"));

MarkerSeries series = miwriter.CreateMarkerSeries("");

GradoParalelismo = 2;

numIterations = 24;

DateTime simTime = new DateTime(2012, 09, 18, 0, 0, 0);

eventoManuales = new ManualResetEvent[GradoParalelismo];

for (int i = 0; i < eventoManuales.Length; i++)

{

eventoManuales[i] = new ManualResetEvent(false);

}

//Cada Iteracion representa una hora de las actividades del dia

for (int n = 0; n < numIterations; n++)

{

series.WriteFlag("Iteration " + n + ": time = " + simTime.TimeOfDay);

//Etapa 1 - Levantarse

for (int i = 0; i < GradoParalelismo; i++)

{

eventoManuales[i].Reset();

var span = series.EnterSpan("Levantadose");

TaskInfo ti = new TaskInfo("Levantadose", i);

ThreadPool.QueueUserWorkItem(Levantarse, ti);

Thread.Sleep(100);

span.Leave();

}

WaitHandle.WaitAll(eventoManuales);

//Etapa 2 -Bañarse

for (int i = 0; i < GradoParalelismo; i++)

{

eventoManuales[i].Reset();

var span = series.EnterSpan("bañandose");

TaskInfo ti = new TaskInfo("bañandose", i);

ThreadPool.QueueUserWorkItem(Banarse, ti);

Thread.Sleep(100);

span.Leave();

}

WaitHandle.WaitAll(eventoManuales);

//Etapa 3 - Desayunar

for (int i = 0; i < GradoParalelismo; i++)

{

eventoManuales[i].Reset();

var span = series.EnterSpan("Desayunandose");

TaskInfo ti = new TaskInfo("Desayunandose", i);

ThreadPool.QueueUserWorkItem(Desayunar, ti);

Thread.Sleep(100);

span.Leave();

}

WaitHandle.WaitAll(eventoManuales);

//Etapa 4 - Salir

for (int i = 0; i < GradoParalelismo; i++)

{

eventoManuales[i].Reset();

var span = series.EnterSpan("Saliendo a trabajar");

TaskInfo ti = new TaskInfo("Saliendo a trabajar", i);

ThreadPool.QueueUserWorkItem(Salir, ti);

Thread.Sleep(100);

span.Leave();

}

WaitHandle.WaitAll(eventoManuales);

simTime = simTime.AddHours(1);

}

Console.ReadKey();

}

Como podemos ver tenemos una variable estática llamada GradoParalelismo, el cual define la cantidad de hilos que van a participar de manera simultanea en la simulación.

Dado que los resultados de cada fase dependen de la fase anterior, usaremos una variable llamada (eventoManuales) con el fin de tener un punto de reset , de tal forma que los hilos no continuaran la siguiente fase hasta que todos hayan finalizado la fase actual.

En este ejemplo , Se ejecutara en una maquina con un Core i7 Processor. Con la variable GradoParalelismo = 2 y ejecuto el código en dos iteraciónes.

Con el fin de tener un idea generalizada de cómo se comporta la aplicación correremos el visualizador de concurrencia, para saber cuál de la etapas se encuentra más equilibrada y desde luego la duración de cada una de ellas.

La imagen que se presenta a continuación muestra el comportamiento de la aplicación sobre el visualizador de concurrencia.

Según la grafica anterior, lo que podemos visualizar, es que el hilo anterior encola los elementos de trabajo y los bloquea mientras avanza el programa. Como se puede visualizar existen varios hilos ejecutando el trabajo (Color Verde). Los hilos no están 100% ocupados, sin embargo , a partir de esta imagen es difícil saber a que horas se lleva cada fase.

En el post anterior , realizamos una introducción de como se usa un SPAN para demarcar la ejecución de una fase. Pero a diferencia del ejemplo anterior lo que desea realizar es tener un Marcador ( Marker) personalizado, en lugar de utilizar el predeterminado.

lunes, 10 de septiembre de 2012

Caller Information con C# en Visual Studio 2012:

 
Mediante el uso de atributos del caller info, usted ahora puede tener información acerca de quien esta llamando un método. Puede obtener la ruta del archivo del código fuente, el numero de la línea, y el nombre del miembro del llamador. Esto puede ser útil para realizar el seguimiento, depuración y sirve como herramienta de diagnostico.
Los atributos de información de llamantes, aparecen como caídos del cielos para personas dedicadas a realizar métodos para diagnostico de una aplicación, ya que normalmente para esto lo que realizaba el desarrollador era la implementación de archivo de registro (log) que guardara lo que sucedía en determinado momento cuando era llamado un método, sin embargo para saber cual método estaba llamado al parámetro de la solución muchas veces era necesario trabajar con reflection para saber el nombre del método, o lo que realizada era implementar la interfaz NotifyPropertyChanged. Ahora sencillamente el desarrollador proporciona el atributo adecuado para los parámetros de una función con los valores que vienen por defecto y magia!!!! AHORA PODEMOS SABER CUAL ES EL METODO QUE ESTA LLAMANDO , sin tanto código.
Para obtener esta información, se utilizan atributos que tienen parámetros opcionales, los cuales tienen un valos por defecto. El espacio de nombre es System.Runtime.CompilerServices.
A continuación le nombro estos atributos:
CallerFilePathAttribute: Ruta completa del archivo que contienen el llamador. Esta ruta esta dada en tiempo de compilación y es de tipo string.
CallerLineNumbreAttibute: Numero de la línea de archivo origen en el cual el método es llamado y es de tipo string.
CallerNameAttribute: Entrega nombre del método o de la propiedad del llamante es de tipo string.
Veamos el siguiente ejemplo en donde tenemos un métodos principal llamado main del cual realizamos un llamado a un método para que imprima la ubicación del archivo del proyecto desde donde se esta ejecutando, la línea de código desde donde se esta llamando, y el nombre de método que lo llama.
El código fuente es el siguiente:
image
Al ejecutar este código lo que presentara en la ventana de consola es lo siguiente:
clip_image002

Ahora veamos que sucede si creamos otro método llamado OtroMetodo y desde el nuevo método llamamos a al método que tiene el decorado con los atributos de Caller Information.
clip_image004

Como podemos visualizar, en la función que llama ahora dice Otro Método y en la línea desde donde se llama es la línea 18 de nuestro código fuente.

DESCARGUE EL CODIGO DE EJEMPLO AQUI












domingo, 2 de septiembre de 2012

USO de Mensajes (MESSAGE) con el SDK del Visualizador de Concurrencia


Cuando se requiere tener un archivo de registro de datos, con el fin de que nos pueda servir para diagnóstico de desempeño de la aplicación o para fines de depuración de código, generalmente lo que hacemos es crear un archivo que guarde la información que se requiere a monitorear, sin .embargo lo que sucede es que este archivo no se revisa constantemente, y en caso de hacerlo, lo más probable es la mayoría de la información guardada en el archivo de registro se omite.
clip_image002
Cuando se requiere este tipo de información se recomienda utilizar la palabra clave Message del SDK del visualizador de concurrencia . Supongamos que vamos a medir la cantidad de tiempo para generar un archivo de log que mida el tiempo requerido para su generación, para una operación de escritura de un archivo.
El código para probar esta funcionalidad lo especifico a continuación y vale la pena resaltar que en el ovalo de color azul se encuentra la palabra clave Message, la cual especifica lo que se va a adicionar en los Markers.
Lo que realiza este código es listar los directorio que están en mi disco duro C, y se almacenara esta información en un archivo de texto en el mismo disco, lo importante es que por cada operación de escritura se monitoreara el tiempo en que realiza dicha escritura.
Al ejecutar el analizador de concurrencia, lo que veremos son unos pequeños rectángulos que representan el mensaje del tiempo de cada escritura, (Ver ovalo de color Naranja en la siguiente grafica), Si usted necesita ver de manera mas especifica la información de salida del mensaje , lo que puede realizar es seleccionar desde el informe el ítem Markers ubicado en la parte inferior izquierda llamado Visible TimeLine Profile y al dar click en ello, podremos visualizar de manera granular la información del mensaje-
clip_image004

Este reporte enumera todos los Markers en el intervalo de tiempo visible actualmente, para este caso son 18 Markers, ya que en mi disco duro únicamente tengo esta cantidad de carpetas, sobre este mismo cuadro podrás visualizar, en tiempo en que tarda en escribir el nombre del directorio al archivo ubicado en el disco D.
Si queremos exportar la información de estos Markers, en este listado existe un botón llamado export el cual me permitirá exportar esta información a archivo de Texto o un archivo csv.
clip_image006
clip_image008
Estos pequeños artículos muestran a ustedes una nueva funcionalidad del para Visualización de concurrencia, sin embargo el ejemplo es lo mas básico y sencillo, con el fin de que las personas que están comenzando a manejar la depuración de concurrencia se les haga mas fácil entender como función. Existen maneras mas complejas de este SDK, como por ejemplo colocando categorías, niveles de importancia y manejo de múltiples Markers. Este tipo complejo de información lo dejare para posteriores post.
 
DESCARGUE EL CODIGO DE EJEMPLO AQUI











USO de Bandera (FLAG) con el SDK del Visualizador de Concurrencia

Cuando se requiere marcar un evento especifico en nuestras aplicaciones en donde no es valioso saber el tiempo en que dura el evento, sino sencillamente en que momento ocurre, lo más adecuado es usar FLAG, lo que hace en realidad es marcar en el canal con un icono en donde ocurrió el evento y desde luego el nombre del mismo. Un ejemplo de esto podría ser saber en qué momento de nuestra aplicación ocurrió un excepción.
Continuando con el ejemplo anterior lo que podremos es ver en qué momento se inicia cada uno de los métodos pero no cuánto dura, la sintaxis del uso del flag es como aparece a continuación:
clip_image002
Al ejecutar el código y analizarlo por medio del visualizador de concurrencia, obtendremos lo siguiente:

clip_image004

Espero el articulo les sirva y cualquier duda estare atento a ella. Adjunto envio codigo fuente del ejemplo.


DESCARGUE EL CODIGO DE EJEMPLO AQUI




Uso de Duración (SPAN): SDK Visualizador de Concurrencia

Como definimos anteriormente, un SPAN representa una fase de la aplicación, en el ejemplo mostrado al inicio de este blog, no es fácil conocer el trabajo realizado por cada uno de los métodos tanto Metodo1 como el Metodo2.
clip_image001



Si revisamos la grafica anterior podermos ver que es lo que esta pasando en el hilo principal, pero no tenemos idea que sucede específicamente,en que momento se esta ejecutanto cada uno de los métodos. Lo que podríamos hacer para deducir que es lo que esta realizando , es revisar cada uno de los segmentos de color verde y mirar el llamado de la pila, para determinar en donde finaliza cada uno de los métodos y donde inicia el siguiente, pero esto no necesariamente me garantiza lo que en verdad esta sucediendo. El nuevo SDK nos ayuda a poder intrumentar nuestras aplicaciones en paralelo, miremos como se puede hacer en el siguiente código.
clip_image003

Al compilar y analizar con el visualizador de concurrencia, obtenemos la siguiente grafica en donde aparece en la columna Izquierda un nueva fila la cual es llamada CANAL, y es nombrada con el espacio de Nombres del SDK, (ConcurrencyVisualizer.Markers), en esta fila ya podemos ver en qué momento se está iniciando y finalizando, cada uno de los métodos con respeto al hilo principal de ejecución. Fijemos que la separación entre cada uno de los métodos conrresponde a la impresión que se realiza en la consola diciendo que el método 1 a terminado.
clip_image005



Como vemos el tiempo de cada uno de los métodos, visualizamos que el metodo1 tarda menos que el Metodo 2 ya que el ciclo del metodo1 va hasta 100 y el del Metodo2 va hasta 200. De hecho si seleccionamos con el Mouse cada uno de los Metodos, podremos saber cual es el tiempo de ejecución de cada uno de ellos, Por ejemplo:
clip_image009 clip_image008

El metodo1 donde el ciclo va hasta 100 tarda 18.5279 Milisegundos y el Metodo2 donde el ciclo va hasta 200 tarda 22.0959 ms.
Fijemos que el ID del hilo asociado con el canal Marker es el mismo ID que del hilo principal, visualizando en la grafica es el Hilo con ID 6544, este ID esta ubicado al lado izquiero del nombre del canal. Esto indica que los eventos del Marker fueron generados desde el hilo principal. Si estos eventos son generado a partir de un hilo diferente, el canal estará asociado con el ID desde el hilo que lanzo el evento.
Espero puedan practicar con el fin de que se familiarizen con el uso de este SDK.

DESCARGUE EL CODIGO DE EJEMPLO AQUI










El nuevo SDK para el visualizador de concurrencia en VS2012

 

El visualizador de concurrencia muestra información importante tanto de la CPU, como de la GPU y recursos importantes como la actividad de DirectX, dispositivos de I/O y de los procesos que se ejecutan entre otros. el visualizador muestra el promedio de utilización de núcleo del proceso. Los procesos libres, los procesos del sistema y otros procesos que son ejecutados en tiempo del sistema.

Por ejemplo si dos núcleos están ocupando en un 50% de su capacidad en un periodo de tiempo determinado, entonces esta vista muestra el procesador lógico que está siendo utilizado.

Esta información puede ser muy valiosa en la investigación de comportamiento de una aplicación, pero a veces es difícil de entender rápidamente cómo los datos que se muestran en los mapas visualizador de concurrencia en el comportamiento de la aplicación. Visual Studio 2012 trae consigo un SDK que permite instrumentar el código con el fin de aumentar las visualizaciones mostradas en la vista Hilos de las visualizador de concurrencia. Estas visualizaciones, denominados marcadores “Marker”, hace que la vista de hilos sea semánticamente entendible porque representan las fases y eventos específicos de la aplicación.

Y después de tanta teoría comencemos con lo interesante, usarlo !!! , miremos donde ubicarlo en el IDE de Visual Studio.

 

clip_image002

En el menú de herramientas en análisis, visualizador de concurrencia

El SDK contiene tres opciones visuales , las cuales son:

1.Span: Representa un intervalo de tiempo en la aplicación. Como lo es una fase de la aplicación.

2. Flag: Representa un único punto en el tiempo ( por ejemplo cuando se llega a un valor predeterminado o cuando ocurre una excepción).

3.Message: Representa un único punto en el tiempo, pero se entiendo como un análogo al clásico evento de estilo trazado.

Para cada una de estas tres opciones generaremos un ejemplo sobre ellas, aunque lo hare con ejemplos básicos para poderlo trabajar.

Vamos a crear un pequeño proyecto con dos métodos, los cuales cada una realizara un ciclo de 1 a 10000, y el otro de 100000 a 20000 con esto comenzaremos a que la aplicación se presentaría de la siguiente manera:

class Program

{

static void Main(string[] args)

{

Metodo1();

Console.WriteLine("Terminado Metodo 1");

Metodo2();

Console.WriteLine("Terminado Metodo 2");

}

private static void Metodo2()

{

for (int i = 0; i < 100; i++)

{

Console.WriteLine(i);

}

}

private static void Metodo1()

{

for (int i = 10000; i < 200; i++)

{

Console.WriteLine(i);

}

}

}

Fijémonos que el código se ejecuta de forma secuencial y se presenta de la siguiente manera:

clip_image004

Ahora vamos a iniciar la depuración con el visualizador de concurrencia de tal formas que realizamos lo siguiente:

clip_image006

Al dar click en iniciar con el actual proyecto, el ejecutable se iniciar realiza la ejecución de cada uno de los métodos de forma secuencial. Y al terminar nos presentara una gráfica como la siguiente:

clip_image008

clip_image010

Utilizando el SDK en el proyecto:

Para comenzar es necesario adición el SDK al proyecto, esto se realizar de la siguiente manera, vamos a al menú de herramientas, opción analizar, luego Visualizador de concurrencia, adicionar el SDK al proyecto.

clip_image012

Aparecera una ventana en donde le preguntara que proyectos de la solución desea adicionar al visualizador de concurrencia, en el caso que el proyectos tenga varios proyectos estos aparecerán en la lista a seleccionar ( ver Grafica).


clip_image016clip_image014

Luego de seleccionar el proyecto , se presiona el botón adicionar sdk al proyecto y aparecerá una nuevamente confirmando que el SDK fue adicionado al proyecto seleccionado, y lo podemos validar al verificar las referencias del proyectos en donde aparecerá una nueva referencia llamada Microsoft.ConcurrencyVisualizer.Markers y luego se da click en el botón Cerrar.

clip_image020 clip_image018

Despues de esto se debe adicionar el espacio de nombres en el código fuente como aparece a continuación:

using System;

using System.Threading.Tasks;

using Microsoft.ConcurrencyVisualizer.Instrumentation;

namespace ConsoleApplicationConcurrent

{

Comencemos ahora las opciones de visualización que trae el SDK de visualización de concurrencia.

clip_image022

En el siguiente articulo comenzaremos con la utilización de alguno de estas nuevas funcionalidades tales como Span, Marker, Message.

jueves, 23 de agosto de 2012

Paralelismo con Tareas ( Task Parallelism)

 

Comencemos enunciando que las tareas son los elementos fundamentales de las programación en paralelo, por lo tanto el paralelismo de tareas es la ejecución de tareas a través de varios procesadores.

El propósito principal del paralelismo es maximizar la utilización del procesador y desde luego mejorar el desempeño de la aplicación. A medida que aumenta la cantidad de procesadores,una aplicación podrá escalarse ya que una tarea podrá ejecutarse en mas procesadores.

Las tareas paralelas tienen unas entradas , que típicamente trabajan con una colección de datos relacionados.

Que son Tareas ( Task)?

En la actualidad existen varios caminos para invocar tareas en paralelo. En los articulo que escribiré sobre ello, hablare sobre esto, iniciando con el método Parallel.Invoke.

Asumamos que tenemos tres métodos ( A,B,C) , y que cada uno de estos métodos son independientes entre si y no tienen relación entre ellos. Si los métodos se ejecutan de maneras secuencial el tiempo de respuesta de ellos será la sumatoria de duración de cada uno de ellos.

Si por ejemplo el MétodoA tarda 10Ms, MetodoB tarda 20Ms, y MetodoC tarda 10MS, el tiempo total de duración cuando se ejecuta de manera secuencial es de 40 Milisegundos.

 

clip_image002

Cuando estos métodos son convertidos en tareas (Task), las tareas son completamente independiente, esto hace que cuando se ejecutan tareas en paralelo ya no es necesario ningún tipo de sincronización tales como lo que hemos vistos en mis artículos anteriores como semaphore o Monitor. Por lo tanto el desempeño en la utilización de tareas es mucho mejor y la porción del código que se ejecuta en una tarea (Task) se vuelve escalable. Además la sincronización como todos sabemos hace mas complejo el mantenimiento y la depuración.

Cuando un grupo de tareas se ejecuta en paralelo, el tiempo de ejecución es igual al tiempo de ejecución de la tarea mas larga. En la siguiente imagen vemos un ejemplo de lo que puede tardar los métodos cuando se ejecutan como tareas desde luego en paralelo, para concluir el tiempo de ejecución es la mitad que cuando se hace de forma secuencial, con este ejemplo asumimos desde luego que hay suficientes procesadores libres por lo menos tres.

 

Captura de pantalla 2012-08-23 a la(s) 16.10.54

 

Las tareas son programadas y asignadas a un hilo (thread), los hilos son ejecutados por un procesador. Un hilo es un camino de ejecución asíncrona sobre un proceso. Como hemos hablado un hilo por si solo no hace nada, la actividad es realizada por los hilos. De hecho el sistema operativo cierra automáticamente un proceso que no tiene hilos. debido a que no existe motivo alguno para que mantenga un proceso que no tiene actividad alguna.

A pesar de esto, un proceso es, sin embargo importante. Provee los recursos necesario para la ejecución de un programa, tales como memoria virtual , la pila y demás recursos necesarios.

Hilos (Threads)

Las tareas se ejecutan sobre los hilos. Los hilos son el motor de su aplicación y representan el código que se esta ejecutando. Entendiendo los hilos fácilmente podremos entender que hace una tarea.

Estos es importante porque parte de la sobrecarga vienen asociadas con las tareas relacionadas con los hilos. Además los hilos tienen gran relevancia cuando se habla de programación en paralelo.

El sistema operativo programa los hilos de forma preventiva. Los hilos son asignados y ajustados con una prioridad especifica y en general son programados por partes iguales basándose de la prioridad de los hilos. A continuación  enumero el porque un hilo puede ser anulado:

 

  • Porque el Hilo excede el tiempo de ejecución.
  • Porque la prioridad de inicialización es alta.
  • Porque se ponen en espera.
  • Porque ocurre una operación de entrada y salida.

Nada en pro de desempeño de la aplicación es gratis, incluyendo los hilos. Los hilos tienen sobrecargas, y esta sobrecarga vienen asociada con la sobrecarga en la pila o stack, almacenamiento local de hilos, y multiplexacion de los contextos de hilos. Por defecto el tamaño pila para cada hilo es de 1 MB. Por ejemplo 200 hilos podrían reservar 200MB de espacio en memoria. El almacenamiento local de hilos es un conjunto de memoria privada reservada por cada hilo y puede también ser significante. Adicionalmente a la sobrecarga de almacenamiento, los hilos tienen un costo de desempeño : por los cambios de contexto.

Gran parte de este costo esta asociado con el intercambio entre el modo Kernel y modo usuario y el canje de un hilo por otro modo de hilo. El costo de cambio de contexto puede reducir el beneficio de hilos adicionales.

Ademas de costo de cambio de contexto, existen otros costos tales como aumento gradual de hilos y su destrucción. El framework de .Net trae una ayuda  para llamada “Thread Pool” , para administrar estos costos y abstraer de complejidad de la creación, iniciación y destrucción de hilos.

El “Thread Pool”  grupo de hilos, comúnmente reúsa los hilos para disminuir los costos de iniciación y destrucción, cuando el hilo ya no se requiere, ele sistema operativo reasigna un trabajo adicional al hilo o lo suspende.

Existen algoritmos para ajustar el Tamaño “Thread Pool”, dinámicamente basados sobre la utilización de los hilos y otros factores.

El Framework 4 de .Net “Thread Pool” es el programador por defecto para las tareas en paralelo. Cuando se inicia una tarea, esta es programada para ejecutarse y ponerse en cola como parte del pool de hilos. Después las tareas son desencoladas y asignadas a ejecutarse sobre el hilo disponible. Afortunadamente esta tarea es transparente para el desarrollador.

En resumen, una tarea es un grupo de estados relacionados, cuando son iniciados son adicionados a la cola pool de hilos. Eventualmente (puede ser instantánea) , una tarea es ejecutada sobre un hilo, el cual es la unidad de ejecución. Desde luego un hilo que pertenezca al pool de hilos.

Cada hilo es asignado y inicialmente ejecutado sobre un procesador en particular, el cual es considerado como la unidad de proceso. El siguiente diagrama muestra la relación entre una tarea, un hilo y un procesador.

clip_image002[5]

Espero este pequeño articulo les ayude a ustedes, a entender un poco sobre como es el comportamiento de una tarea  y en mis proximos articulos hablare sobre los metodos parallel invoke, TaskFactory.StartNew, Task.Start. Saludos….

viernes, 13 de julio de 2012

COMO TENER LAS CARACTERISTICAS ASYNC EN VISUAL STUDIO 2010.


En la actualidad ya esta en la versión Release Candidate de Visual Studio 2012, el cual contiene entre otras nuevas funcionalidades la nueva forma de Desarrollar la programación asíncrona, para los que no desean aun descargar esta versión, y tienen Visual Studio 2010, Microsoft provee una extensión de esta librería proporcionando la nueva sintaxis para el desarrollo asíncrono.
clip_image002
Los requisitos para la instalación de esta extensión son los siguientes:
Visual Studio 2010 con SP1.
Esta extensión liberado por CTP (Community Technology Preview) Asyn es una ayuda para el desarrollador para que conozca las nuevas herramientas para programación asíncrona. Microsoft advierte que el uso de esta extensión es bajo el riesgo de quien lo instala, esta extensión no se recomienda para liberarla en producción, aunque por petición de los desarrolladores se podrá realizar como mencione antes bajo el riesgo de quien lo desee hacer.
Adicional a ello esta versión es compatible con SilverLight 5, Windows Phone SDK 7.1 (Mango), Visual Studio Express.
Cuando no se tiene actualizado Visual Studio 2010 con esta extensión al intentar usar async o await nos aparecerá de la siguiente forma:
clip_image004
El proceso de instalación tarda aproximadamente 10 minutos, cuando se finaliza el proceso de instalación saldrá la siguiente ventana, mostrándonos los productos que se actualización con esta extensión.
clip_image006
Luego podremos nuevamente abrir la solución con la cual deseamos utilizar async o await y automáticamente aparecerá ejemplo.
clip_image007
clip_image008
De esta forma podremos utilizar esta poderosa forma de codificar para programación asíncrona.












martes, 19 de junio de 2012

Uso de la Clase Mutex con C#


Continuando con los artículos que tienen que ver con la sincronización de hilos a continuación quiero abordar una clase llamada Mutex (Mutual Exclusion), cuya funcionalidad es asegurar que solamente un hilo pueda tener a acceso a un recurso, o porción de código, esta clase puede ser usada para evitar que múltiples instancias de una aplicación sean iniciadas.
   
Aparentemente la funcionalidad de la clase Mutex es muy parecida a Lock, una de las grandes diferencias entre ellas es que Mutex es una Clase y Lock es una Instrucción, la funcionalidad de Mutex es mayor ya que permite manejar bloqueo a nivel de Sistema Operativo, de tal forma que actua a nivel de proceso.
   
Cuando un Hilo adquiere una exclusión mutua (mutex), el siguiente Hilo que intenta adquirir dicha exclusión mutua se suspende hasta que el primer subproceso libera la exclusión mutua.
   
Existen dos tipo de exclusiones mutuas: exclusiones mutuas locales y exclusiones mutuas del sistema con nombre.
   
Si crea un objeto Mutex con un constructor que acepta un nombre, se asocia a un objeto del sistema operativo con dicho nombre. Las exclusiones mutuas del sistema con nombre son visibles en todo el sistema operativo y se pueden utilizar para sincronizar las actividades de los procesos.
   
Con respecto al desempeño de la utilización de Mutex Vs Lock, La instrucción Lock es mucho mas rápida que la utilización de la clase Mutex.
   
Para utilizar la clase Mutex , se requiere el método WaitOne el cual obtiene el bloqueo exclusivo de un contenido a bloquear. Dicho bloque es liberado con el método ReleaseMutex. De la misma forma que  se bloqueo con Lock , la clase Mutex puede ser liberada únicamente con la terminacion del hilo que la llamo.
   
      private static Mutex mut = new Mutex()
   
Cuando se instancia una clase mutex de esta manera se hace una sobrecarga de este constructor llamando al contructor mutex(false), donde especifica como por defecto false , esto quiere decir que el hilo no es propiertario de el Objeto Mutex.
   
El como se usa se presenta a continuación.
   
    mut.WaitOne();
                    Console.WriteLine("{0} Ingresando de Codigo Protegido",
                    Thread.CurrentThread.Name);
    mut.ReleaseMutex();
   
Miremos en el ejemplo utilizado con la instrucción lock, como se usa con exclusión mutua.
   
   public void Sumar()
            {
               mut.WaitOne();
                    Console.WriteLine("{0} Ingresando de Codigo Protegido",
                    Thread.CurrentThread.Name);
                    resultado = operador1 + operador2;
                    //Bloqueamos el Hilo actual durante un segundo
                    Thread.Sleep(1000);
                    Console.WriteLine("El resultado de la Suma es:" + resultado);
                    Console.WriteLine("{0} Saliendo de Codigo Protegido\r\n",
                    Thread.CurrentThread.Name);
               mut.ReleaseMutex();
           }


Un uso común para la clase Mutex , es el aseguramiento de la ejecución de una única instancia de un programa.
En los próximos post continuaremos con la explicación de los estados de ejecución de un hilo y desde luego con algunos ejemplos sobre ellos.





domingo, 10 de junio de 2012

Cuando sincronizar con Semaphore en C#.


Continuando con los post acerca de la programación con hilos, el día de hoy quiero explicarles otro método de sincronización de hilos de los cuales ya hemos visto lock , ahora veremos el método Semaphore, el cual limita el numero de hilos que puede acceder a un recurso o un grupo  de recursos de manera concurrente.
Para explicar de una manera mas coloquial un semaphore lo podemos asimilar como a un cajero de banco , donde la fila de depositantes son los hilos, los cuales esperan a que el cajero termine de atender para continuar con los que están en fila, con esto podemos concluir que un semaphore tiene una capacidad y si la capacidad llega a su valor máximo los demás hilos deben esperar a que se desocupe el semaphore para que los pueda atender.
Semaphore_1Semaphore_2
Para instanciar un objeto se tipo Semaphore , no sobra decir que se requiere el espacio de nombres System.Threading,y se debe tener en cuenta que el constructor de Semaphore requiere de mínimo dos parámetros, el primero es el numero de espacios de los recursos disponibles cuando el objeto crea una instancia, el segundo parámetro es el numero máximo de espacios disponibles o capacidad total. Si desea reservar algunos espacios para la llamada a un hilo, esto se puede realizar con el primer parámetro, de tal forma que el primer parámetro es mas pequeño que el segundo.
Semaphore sem = new Semaphore(Recursos Disponibles, Recursos Maximos).
Por ejemplo si creamos la siguiente instancia:
Semaphore sem = new Semaphore(3, 3);

Esto para nuestro ejemplo del cajero quiere decir que un cajero podrá atender tres personas al mismo tiempo y en el momento que se desocupe de una de esas personas y existiesen mas personas en la fila , sencillamente podrá ingresar ya que al desocuparse el semaphore quedara (2,3) , y como tenemos otra persona al ingresar el semaphore quedara (3,3).


Después de Instanciar el objeto semáforo, simplemente se requiere realizar un llamado al método WaitOne(),  de tal forma que con el llamado a este método se limite la porción de código a la cual desea limitarse el numero de hilos especificados al instaciar el objeto semaphore.

Sem.WaitOne(); entra al semáforo y el semáforo se decrementa.

Cuando son finalizados los procesos , es necesario llamar el método Release(), para liberar el espacio de recursos disponibles. El conteo de un semáforo disminuye cada vez que el hilo ingresa al semaphore y se incrementa cada vez que sale el hilo del semaforo.

Sem.Release(); Libera el semáforo y el semáforo se incrementa;

Sem.Release(int n); Libera n entradas del semáforo.

Cuando el conteo de semáforo es cero, los otros subprocesos esperan hasta que sea liberado algún hilo del semáforo, Cuando todos los hilos se encuentran liberados del semaphore el valor del conteo es le máximo,

A continuacion presente un pequeño ejemplo muy comun usado para la explicaciones de las funcionalidad de Semaphore, y se basa en el ejemplo que hemos estado hablando acerca del cajero.

   1:  using System;
   2:  using System.Threading;
   3:  namespace SemaphoreThreading
   4:  {
   5:      class Program
   6:      {
   7:          static void Main(string[] args)
   8:          {
   9:          for (int i = 0; i < 10; i++)
  10:              {
  11:                  threads[i] = new Thread(C_sharpcorner);
  12:                  threads[i].Name = "thread_" + i;
  13:                  threads[i].Start();
  14:              }
  15:             Console.Read();
  16:   
  17:          }
  18:   
  19:         static Thread[] threads = new Thread[10];
  20:          static Semaphore sem = new Semaphore(3, 3);
  21:          static void C_sharpcorner()
  22:          {
  23:              Console.WriteLine("{0} en Fila", Thread.CurrentThread.Name);
  24:              sem.WaitOne();
  25:              Console.WriteLine("{0} en atencion", Thread.CurrentThread.Name);
  26:              Thread.Sleep(300);
  27:              Console.WriteLine("{0} Saliendo", Thread.CurrentThread.Name);
  28:              sem.Release();
  29:          }
  30:   
  31:      }
  32:  }



El resultado de la aplicacion es la siguiente:

image

Si revisamos el resultado del ejemplo, veremos que maximo se estan atendiendo 3 personas y a medida que van siendo atendidos , las demas personas siguen en atencion, pero teniendo en cuenta que la cantidad maxima que atiende el cajero de manera concurrente son 3.


DATOS IMPORTANTES:

No se garantiza que la ejecución de hilos con Semaphore tenga un orden puede ser LIFO como puede ser FIFO.

La clase Semaphore no garantiza la identidad del hilo sobre el llamado de los métodos WaitOne() o Release. Es responsabilidad del desarrollador asegurarse de que los hilos no se libere el semáforo demasiadas veces.

Por ejemplo, supongamos que un semáforo tiene un conteo máximo de dos, y el que el hilo que A y el hilo B, ambos entran al semaforo. Si un error de programación el Hilo B hace que se llame a Release dos veces, ambas llamadas son exitosas. El recuento en el semáforo está llena, y cuando finalmente el subproceso A llama a Release, un SemaphoreFullException se lanza.

Los semáforos son de dos tipos: semáforos locales y semáforos con nombre del sistema.

Si crea un objeto Semaphore mediante un constructor que acepta un nombre, este se asocia con un semáforo del sistema operativo del mismo nombre.

El nombrado de los semáforos es accesible a través del sistema operativo y puede ser usado para sincronizar actividades de los procesos.

Puede crear objetos multipleSemaphore que representan el mismo semáforo con nombre del sistema, y se puede utilizar el OpenExisting () para abrir una ya existente sistema de semáforo con nombre.

Un semáforo local sólo existe dentro de su proceso. Puede ser utilizado por cualquier hilo en su proceso que tiene una referencia al objeto semáforo local. Cada objeto es un semáforo semáforo local por separado.

Diferencias con Lock Y Semaphore:

Con Lock lo que se permite es que solamente un hilo pueda entrar a la parte de código bloqueada y el bloqueo no es compartido con cualquier otros procesos, Semaphore hace lo mismo que lock pero permite que un x numero de hilos pueda entrar a la porción de código de manera concurrente.

En el próximo post analizaremos el uso de Mutex, y espero este pequeño aporte pueda aclarar a ustedes una nueva forma de poder sincronizar el uso de hilos.

martes, 29 de mayo de 2012

Utilización de la palabra Lock en aplicaciones Multihilo.

 

Muchas veces en aplicaciones multihilo, necesitamos controlar que mientras un hilo este ejecutando un método, otro hilo no vaya a ejecutar el mismo método hasta que el hilo1 termine de procesar el método, en otras palabra que el método no se ejecute al mismo tiempo por dos hilos diferentes.
Este tipo de bloqueo se puede realizar a través de una palabra reservada llamada LOCK , que como dije anteriormente no permitirá que un hilo vaya a entrar a un fragmento de código , mientras otro hilo lo este ejecutando, si un hilo intenta entrar al fragmento de código que se encuentra dentro de un LOCK, este hilo esperara a que el otro hilo termine.
La declaración de LOCK Hace un llamado al método Monitor.Enter y al finalizar al método Monitor.Exit con un try / Finally como se muestra a continuación:
Monitor.Enter (_locker);
try
{
  <procedimientos>
}
finally
{
Monitor.Exit (_locker);
}






Veamos el siguiente ejemplo en donde vamos a crear una aplicación de consola llamada Calculador_Thread la cual contiene una clase que tiene tres métodos que reciben dos números respectivamente e imprime la suma de dichos dos números, resta y multiplicación respetivamente.
clip_image002
en dicha clase creamos los métodos de la siguiente manera:
clip_image004
Creamos una detención de la ejecución de los hilos por un tiempo de 1 Segundo con Thread.Sleep(1000), para cada uno de los métodos en el main de la aplicación creamos un hilo de tal forma que cada operación sea realizada en un hilo diferente. El código de la aplicación main lo podemos visualizar a continuación:
clip_image005
Al ejecutar esta aplicación de esta forma podemos visualizar el siguiente resultado.
clip_image007
 
Fijemos que a pesar de la generación de la espera para la ejecución de los hilos el resultado de la variable resultado siempre es la multiplicación de dichos dos números, esto porque las operaciones se están ejecutando de manera paralela y la variable resultado puede ser modificada mientras dos hilos están ejecutándose al mismo tiempo. Que sucede si detenemos la aplicación y volvemos a ejecutarla?
clip_image009
Fijemos que debido a la ejecución multihilo, en algunos momentos un método se ejecuta antes que otro, a pesar de que el orden de ejecución de los hilos para este caso primero es la suma, luego la resta y por ultimo la multiplicación, sin embargo todo depende de que tan ocupado este el procesador donde se esta ejecutando el hilo creado. Sin comparamos la ejecución de la aplicación con respecto a la anterior vemos que el método de multiplicación se realizo en segundo lugar.
Utilicemos ahora la palabra reservada Lock la cual nos ayudara a que el fragmento de código sea ejecutado y nos alcance a presentar el valor de la variable resultado al imprimirla en pantalla , a pesar de que otro hilo este intentando modificar la variable resultado, de tal forma que el código de la clase operaciones quedara de la siguiente forma:
clip_image011
El resultado final cuando realizamos el bloqueo de la ejecución del fragmento de código es el siguiente:
clip_image013
Para finalizar este post es necesario que el desarrollador como buena práctica de la utilización de la palabra Lock nunca intente bloquear una variable pública ya que se convertiría en un problema para la administración de la varia

















jueves, 24 de mayo de 2012

MultiThread , Conceptos Generales


Para continuar con el tema de hilos y multihilos , vale la pena recordar que las aplicaciones concurrentes pueden correr sobre un computador que posee un solo procesador, pero las aplicaciones paralelas requieren de múltiples procesadores.
Cuando tenemos una aplicación que usa múltiples hilos en un computador que tiene un procesador con un solo núcleo, para el usuario los hilos aparentemente trabajan de forma paralela, pero lo que en realidad esta sucediendo es que el sistema operativo intercala los hilos, este comportamiento es llamado Interleaving (Intercalado), y el intercalamiento se basa sobre prioridades de hilos y otros factores que para este post no comentare, tal vez mas adelante profundizaremos sobre estos temas. En la actualidad existen dos tipos de paralelismo los cuales mecionare a continuación:
· Paralelismo Lógico: Cuando un procesador es compartido por varios hilos.
· Paralelismo Físico: Cuando en un equipo de computo existen varios procesadores con múltiples núcleo y el trabajo es descompuesto en tareas , y cada tarea es realizada por un procesador independientemente.




Para el intercalamiento de los hilos, al estar en ejecución un hilo, y si se quiera iniciar “al mismo tiempo la ejecución de otro hilo”, lo que hace el sistema operativo es que conserva el estado de esta hilo, lo detiene e inicia la ejecución del siguiente hilo y de esta manera trabaja el intercalamiento.

Para la ejecución de código paralelo como hemos visto requiere de múltiples núcleos , así que los hilos pueden ejecutarse en paralelo sin necesidad de intercalarse. Idealmente usted se deberia tiene un hilo por cada procesador disponible.


Veamos algunos ejemplos para la creación de hilos, teniendo en cuenta que el espacio en el framework .Net para el manejo de hilos es System.Threading. se puede crear un hilo de la siguiente forma:
Thread t = new Thread(metodo)
Los hilos comparte información si tienen una referencia común sobre el mismo objeto, en el siguiente ejemplo visualizaremos la impresión de un texto que se encuentra en el método impresión, y ejecutamos dos hilos, el hilo principal y el hilo secundaria.
 
   1:  class PruebaHilos
   2:   
   3:  {
   4:   
   5:  static void Main()
   6:   
   7:  {
   8:   
   9:  //Creacion de la instancia de la clase
  10:   
  11:  PruebaHilos tt = new PruebaHilos();
  12:   
  13:  // Creacion del hilo secundario, llamado al metodo Impresion e inicio de ejecucion del Hilo
  14:   
  15:  new Thread(tt.Impresion).Start();
  16:   
  17:  //ejecucion de Hilo Principal, Que llama al metodo Impresion
  18:   
  19:  tt.Impresion();
  20:   
  21:  Console.ReadLine();
  22:   
  23:  }
  24:   
  25:  // Create a common instance
  26:   
  27:  // Note that Go is now an instance method
  28:   
  29:  void Impresion()
  30:   
  31:  {
  32:   
  33:  Console.WriteLine("Ejecucion de Hilo");
  34:   
  35:  }
  36:   
  37:  }



El resultado de este proyecto es que cuando se ejecuta tanto el hilo primario como el hilo secundario, los cuales llaman a método impresión, imprimirá dos veces la palabra YaPaso, como aparece a continuación.

clip_image002

En el siguiente ejemplo lo que veremos es la creación de una variable de tipo boolean la cual comparte información en la ejecución de los dos hilos, dicha variable será controlada desde el método, en donde si un hilo ya paso por el método , entonces la variable será modificada a un valor true y solo se imprimirá una sola vez la palabra ejecución de Hilo, con este pequeño ejemplo lo que podemos verificar es que los hilos comparte información entre si con respecto a las variables.
   1:  class PruebaHilos
   2:   
   3:  {
   4:   
   5:  static bool YaPaso;
   6:   
   7:  static void Main()
   8:   
   9:  {
  10:   
  11:  //Creacion de la instancia de la clase
  12:   
  13:  PruebaHilos tt = new PruebaHilos();
  14:   
  15:  // Creacion del hilo secundario, llamado al metodo Impresion e inicio de ejecucion del Hilo
  16:   
  17:  new Thread(tt.Impresion).Start();
  18:   
  19:  //ejecucion de Hilo Principal, Que llama al metodo Impresion
  20:   
  21:  tt.Impresion();
  22:   
  23:  Console.ReadLine();
  24:   
  25:  }
  26:   
  27:  //Metodo que imprime Ejecucion de Hilo
  28:   
  29:  void Impresion()
  30:   
  31:  { 
  32:   
  33:  if (!YaPaso) 
  34:   
  35:  {
  36:   
  37:  YaPaso = true; 
  38:   
  39:  Console.WriteLine("Ejecucion de Hilo");
  40:   
  41:  }
  42:   
  43:  }
  44:   
  45:  }
  46:   




El resultado de este ejemplo es el siguiente:

clip_image004

En el trabajo con hilos (Threads) o subprocesos existen términos importantes que debemos manejar
Algunos términos importantes:

Sobre-subscripcion: ocurre cuando el numero de hilos excede el numero de procesadores disponibles. Cuando esto sucede el intercalado ocurre para los hilos que comparten un solo procesador.

Sub-Suscripcion: ocurre cuando hay un numero menor de hilos que procesadores disponibles, cuando esto pasa existen procesadores inactivos y una menor utilización optima de CPU.
Desde luego la meta es la utilizar al máximo la CPU, mientra exista un balance entre la sobre-suscripcion y sub-subscripcion

Un hilo puede correr sobre dedicado a un procesador o atraves de otros procesadores. Los hilos ejecutados por un solo procesador poseen una afinidad de procesador, y esto hace que sea mas eficiente.

La programación y lanzamiento en ejecución de un hilo sobre otro nucleo de procesador causa perdidas de cache, acceso local de memoria como resultado de perdida de cache, y exceso de swticheo. Esto es llamado cross- Core swtich.

Sincronizacion.

La sincronización es la herramienta mas común usada para crear ambientes para hilo seguro Thread-Safe de hilo, donde se encuentra el modo Kernel y modo usuario.
Multihilo implica creación de multiples hilos. Los pasos requeridos para la creación de hilos son relativamente sencillos, pero es necesario tener cuidado con la gestión de los hilos ya que manejar aplicaciones Multihilo implica un manejo mas complejo que las aplicaciones tradicionales
Por ejemplo una aplicación con un solo hilo es sincronizada con los recursos de modo Kernel.
Compartir información es la segunda razón para la contención entre multiples hilos y los requerimiento de sincronización.
La contención ocurre cuando un hilo no puede obtener una sicronizacion de objetos o acceso a información compartida durante un periodo de tiempo. Los hilos típicamente se bloquean hasta que la entidad este disponible.
Un tipo de bloqueo es el llamado spinning. Las aplicaciones tienen la opción de spinning en modo usuario, consumen ciclos de CPU pero evitan el switcheo en modo Kernel. Despues de un corto tiempo, el hilo puede volver a intentar adquirir el recurso que es compartido. Si la contesion es corta, se puede adquirir con éxito el recurso sobre el segundo intento para evitar el bloqueo y el switcheo en el contexto relacionado.
Spining para sincronización es considerado un sincronización ligera, Microsoft ha adicionado tipo tales como la estructura SPINWAIT de Framework de .net para este propósito, por ejemplo spining es usado para colecciones concurrentes importante considerar el espacion de nombres System.Collection.Concurrent, para crear hilo seguros y colleciones libres de bloqueos.
Las aplicaciones paralelas se basan se alguna manera en sincronización,. Aveces consideramos que la sincronización es un mal necesario. El exceso uso de sincronización es malo, porque las aplicaciones en paralelo funcionan mejor sin impedimento de cualquier tipo. Serializar una aplicación paralela va en contra de un buen desempeño de la aplicación. De hecho la mejora de la velocidad de una aplicación en paralelo depende de gran parte que porción de código se ejecuta secuencialmente. Por ejemplo cuando una aplicación corre un 40% de forma secuencial, el valor máximo posible de velocidad que puede proveer en teoría seria de un 60%.
En el proximo post hablare de una palabra reservada llamada lock la cual es usada de alguna forma para sincronizar la utilización de hilos en aplicaciones multihilo.