Programación Concurrente y Programación Paralela

 Introducción


 

Es sencillo confundirse con estos dos términos, incluso son temas ligados a la tecnología con la que desarrollamos, es decir, hay runtimes/interpretes/librerías que nos prometen poder realizar más de una tarea al mismo tiempo pero en ocasiones por conveniencia/limitaciones/configuración terminan siendo concurrentes o paralelas sin darnos ni cuenta.

Esta entrada de blog no está enfocada a ningún lenguaje de programación, la intención es explicar qué son y cómo se aplican estas técnicas, así mismo es como el "Hola Mundo", ambas técnicas tienen mucha tela de la cual cortar y dan para varias entradas de blog cada una.


Definición

¿Qué es la programación concurrente?

Es una técnica de programación en la cual definimos el comportamiento necesario para que uno sólo hilo realice más de una tarea alternando entre ellas.

Analogía

Imagina que deseas prepararte una taza de café soluble (Por simplicidad del ejemplo), ¿Qué pasos seguimos para preparar café? 

  • Calentamos agua
  • Servimos el agua caliente en una taza
  • Añadimos el café junto con cualquier otro aditamento que nos agrade 
¿Qué pre requisitos o procesos escondidos hay?
  • Encender tu calentador/estufa/etc
  • Poner a calentar el agua
  • Verificar el estado/temperatura del agua 
  • Juntar todos los ingredientes/materiales (Azúcar, cucharas, leche, etc)
  • Lavar los aditamentos (Posiblemente tu taza estaba sucia)
Podemos optimizar el proceso de muchas maneras pero básicamente puedes

  • Lavar todo lo necesario
  • Poner a hervir agua
  • Mientras el agua hierve juntar los ingredientes adicionales
  • Realizar preparativos (Tal vez te guste servir el café antes que el agua)
  • Añadir el agua 
Aunque en realidad solo realizabas una sola cosa al mismo tiempo (No puedes usar el fregadero para lavar al mismo tiempo que manipulas la estufa), realmente se avanzo en varias cosas al mismo tiempo, a pesar de que en realidad saltamos de una actividad a otra.

¿Qué es la programación paralela?

Es una técnica de programación en la que desplegamos múltiples hilos para realizar múltiples tareas, así efectivamente podemos realizar más de una tarea al mismo tiempo.

Analogía 

Tomemos de base la analogía de programación concurrente pero añadamos otra persona, tu mamá por ejemplo.

Puedes pedir a tu mamá que te ayude a calentar el agua mientras tu juntas todos los ingredientes en la mesa de trabajo, adicional mente tu mamá puede arreglar la mesa mientras tu sirves el café en la taza y se pueden sentar a tomar café juntos :)

En esta analogía podemos ver que dividimos el trabajo entre dos personas, añadimos carga de trabajo (limpiar la mesa) y multiplicamos el resultado (2 tazas de café) en esencialmente el mismo tiempo 
(factores externos como el tiempo en el que el agua se calienta no dependen de cuantas personas estén trabajando en la tarea).


¿Cuándo usar cada una?

Principalmente va a depender de la capacidad de tu hardware y de tu lenguaje de programación, es importante entender que se pueden combinar, tú no puedes hacer que tu computador realice más tareas de las que es capaz al mismo tiempo, osea que si tu CPU es de 8 Cores, no podrás tener más de 8 tareas en paralelo, eso quiere decir que en la vida real nuestro computador tira de ambas al mismo tiempo, la técnica que une ambos mundos se llama Programación Asíncrona y ya estaré escribiendo al respecto en el blog.

Algo muy importante a tener en cuenta es que el añadir más hilos a tu tarea no siempre la hace más rápida, ya que temas como manejo compartido de memoria o despliegue de recursos adicionales puede bloquear tus hilos y terminar con resultados muy similares a programación de un solo núcleo, además como vimos en nuestra analogía, para preparar dos cafés necesitas 2 tazas, más café y el doble de agua, por lo que los pasos de lavar las tazas o hervir el agua tomarán más tiempo y la optimización está en el juntar los ingredientes y  arreglar la mesa.
Saliendonos de nuestra analogía, se puede dar el caso en el que por optimizar tareas que eran veloces en sí mismas, terminamos añadiendo carga de procesos más lentos que la tarea original resultando en reducción de velocidad, para poder identificar estos cuellos de botella se necesita: practica (dale sin miedo), análisis de bloqueos (temas de memoria compartida) y análisis de algoritmos (Complejidad computacional).

Comentarios

Entradas populares de este blog

Smart Pointers en Rust

Iniciamos