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.

No hay comentarios:

Publicar un comentario