programacion-asincronia-concurrencia

Qué es la programación asíncrona

La programación asíncrona es un conjunto de técnicas que permite a las aplicaciones realizar múltiples tareas simultáneamente, sin bloquear el flujo de ejecución principal.

Si tu ordenador no hiciera más que una única cosa, no sería muy útil. Imagina que cada vez que abres un fichero, o visitas una página web, tu ordenador se quedara “congelado” hasta que terminara. ¡No sería muy práctico!

De hecho, tu ordenador hace miles de tareas de forma “simultánea”. Atiende el WiFi, pinta la pantalla, lee el disco duro, ejecuta un programa, y lee el teclado. Todo eso lo hace “más o menos” a la vez.

programacion-asincronia-concurrencia

Tu CPU, haciendo malabares con los procesos

De la misma forma, tu debes preparar tus programas para que hagan varias cosas “a la vez”. Eso es a lo que llamamos programación asíncrona, a crear programas que sean capaces de funcionar de forma no totalmente secuencial.

Ventajas de las asincronía

¿Por qué es importante añadir asincronía a tus programas? Bueno, hay varios motivos y ventajas asociados con poder ejecutar tareas de forma no secuencial.

El principal motivo para aplicar sincronía es una mejora de la experiencia del usuario en forma de responsividad. Es decir, en darle una respuesta al usuario al través del interface de usuario.

Sin asincronía, por ejemplo, tu programa no podría ni poner una ventana de “loading” con un circulito dando vueltas, mientras cargas datos de algún lado. Se quedaría bloqueada y no podrías hacer absolutamente nada.

El otro gran motivo es que, en determinadas circunstancias, puede suponer una mejora de la eficiencia de recursos. Recursos que son limitados, y pueden hacer de cuello de botella.

Por ejemplo, imagina que el propio procesador está parado, esperando a que se reciba una respuesta desde una web. Con la asincronía es posible aprovechar esa espera para “meter” otros cálculos en medio.

Dificultades de la programación asíncrona

Por supuesto no todo iban a ser ventajas. La programación asíncrona es objetivamente más difícil que la programación secuencial o síncrona. Siempre lo ha sido, y siempre lo será.

Esto es así simplemente porque es inherentemente más compleja. Siempre va a ser más complicado manejar varias cosas a la vez, que una sola. Igual que hacer malabares con cinco pelotas, es más difícil que con una.

Uno de los problemas que vais a tener que considerar es la sincronización temporal. Ahora una cosa no va detrás de otra, si no que trascurren en paralelo o semi paralelo.

Así que tu cabeza debe dejar de pensar en tu programa como una serie de tareas que se ejecutan secuencialmente, para pensar en un cronograma con varias líneas de ejecución que pueden ser paralelas e interferir de forma deterministas.

Otro gran problema es el acceso a recursos compartidos. Si un recurso está siendo de forma activa por un proceso, es muy probable que otro proceso no pueda usarlo. Si los dos intentan acceder a él, seguramente tengas un error.

Finalmente, también vas a tener dificultades de compartir la memoria. Es incluso posible que un proceso esté “haciendo sus cosas” y otro proceso le modifique una variable. O que una tarea no pueda acceder a la memoria de la otra.

Todos estos problemas no los teníamos en la programación síncrona. Para gestionar estas cosas hemos creado un montón de herramientas y recursos, como los mutex, semáforos, monitores… pero aún así, siempre vas a tener una complejidad añadida al diseño.

Mecanismos para programación asíncrona

Además de herramientas que ya he mencionado, los distintos lenguajes de programación han incorporado diversos mecanismos para que implementar la asincronía sean más sencillos.

Algunos de ellos son:

  • Callbacks / Eventos: Funciones que se pasan como argumentos a otras funciones y se ejecutan después de que una operación se completa.
  • Promesas / futures: Objetos que representan un valor que puede estar disponible ahora, en el futuro o nunca.
  • Async / Await: Sintaxis que permite escribir código asincrónico de manera más similar al código síncrono.
  • Threads / Hilos: Los hilos permiten ejecutar múltiples tareas en paralelo dentro del mismo proceso.
  • Co-rutinas: Son funciones que pueden pausar su ejecución y ceder el control a otras co-rutinas.
  • Event Loop: Mecanismo que permite manejar operaciones de entrada/salida de manera no bloqueante.

Estos mecanismos proporcionan diversas formas de gestionar la ejecución de tareas concurrentes y asincrónicas, cada uno con sus propias ventajas y desventajas.

Por supuesto, la elección del mecanismo adecuado depende del lenguaje de programación y el tipo de aplicación que estés desarrollando. Los iremos viendo en profundidad en los distintos artículos de este capítulo.