Concurrencia y paralelismo aparecen en todo desarrollo moderno: servidores web, videojuegos, ciencia de datos y sistemas embebidos. Ambos conceptos hablan de manejar varias tareas, pero no son sinónimos. Comprender qué persigue cada uno y cuándo aplicarlo evita diseños costosos o soluciones frágiles.
En este primer tema definimos los dos términos, resaltamos sus diferencias y revisamos ejemplos cotidianos que los vuelven intuitivos. También aclaramos escenarios donde existe concurrencia sin paralelismo y viceversa, una distinción esencial para planificar correctamente el uso del hardware disponible.
Son estrategias para abordar varios trabajos que compiten por recursos. La concurrencia organiza y coordina tareas que pueden solaparse en el tiempo. El paralelismo ejecuta tareas al mismo tiempo en unidades de cómputo distintas (hilos, núcleos, GPU). Muchas aplicaciones combinan ambas: necesitan coordinar tareas independientes y, cuando hay hardware suficiente, ejecutarlas simultáneamente.
La concurrencia es la capacidad de un sistema para gestionar varias tareas que avanzan de manera entretejida. No implica que se ejecuten literalmente al mismo tiempo; significa que el diseño permite alternar entre ellas de forma segura. Sistemas operativos, bucles de eventos y servidores de peticiones son ejemplos típicos: coordinan recursos, deciden qué tarea sigue y mantienen la coherencia del estado compartido.
El paralelismo se centra en ejecutar tareas simultáneas usando múltiples unidades de ejecución. Puede ocurrir en diferentes niveles: varios núcleos de CPU, instrucciones vectoriales (SIMD) o cálculo masivo en GPU. El objetivo es acelerar un trabajo dividiéndolo en partes que puedan resolverse al mismo tiempo sin bloquearse entre sí.
La concurrencia es un modelo de organización; el paralelismo es un modelo de ejecución. Un programa puede estar diseñado para manejar muchas solicitudes sin que ninguna se bloquee (concurrencia), aun cuando un solo núcleo las ejecute en turnos. A la inversa, una tarea de ciencia de datos puede dividirse en partes independientes y ejecutarse en distintos núcleos (paralelismo) sin necesidad de coordinar interacciones complejas entre ellas.
En resumen: la concurrencia resuelve qué tareas existen y cómo se relacionan; el paralelismo resuelve cuántas de ellas se ejecutan exactamente al mismo tiempo.
Concurrencia sin paralelismo: en un CPU de un solo núcleo, el sistema operativo intercala procesos o hilos. Cada tarea progresa en turnos breves, pero nunca hay dos ejecutándose a la vez. Un bucle de eventos (por ejemplo, en JavaScript del lado del servidor) también es concurrente: gestiona muchas operaciones de entrada/salida alternando callbacks sin usar varios núcleos.
Paralelismo sin concurrencia: un cálculo numérico que divide una matriz en bloques independientes y los envía a cuatro núcleos. Cada bloque se procesa de forma simultánea y sin compartir estado; no necesita coordinar interacciones complejas, solo reunirse al final para combinar resultados. De modo similar, tareas embarrassingly parallel en GPU (como aplicar el mismo filtro a millones de píxeles) son paralelas pero casi no requieren mecanismos de concurrencia.
Entender esta diferencia permite elegir herramientas: concurrencia para orquestar, paralelismo para acelerar cuando el hardware lo permite.