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….