Conceptos de concurrencia asíncrona¶
La mayoría de los programas que usan otros modelos de concurrencia están
escritos de manera lineal, y confían en los hilos subyacentes o en la gestión
de procesos al tiempo de ejecución del lenguaje o el sistema operativo para
cambiar el contexto según corresponda. Una aplicación basada en asyncio
requiere que el código de la aplicación maneje explícitamente los cambios de
contexto, y usar las técnicas para hacer eso correctamente depende de la
comprensión de varios conceptos interrelacionados.
El marco proporcionado por asyncio
se centra en un bucle de eventos un
objeto de primera clase responsable de manejar eficientemente los eventos de
E/S, eventos del sistema y cambios de contexto de la aplicación. Varias
implementaciones del bucle se proporcionan, para aprovechar eficientemente las
capacidades del sistema operativo. Mientras que un valor por defecto razonable
es usualmente seleccionado automáticamente, también es posible elegir una
implementación del bucle de eventos en particular desde dentro de la
aplicación. Esto es útil bajo Windows, por ejemplo, donde algunas clases de
bucle agregan soporte para externos procesos de una manera que puede cambiar
algunas eficiencias en la E/S de red.
Una aplicación interactúa con el bucle de eventos explícitamente para registrar código a ejecutar, y permite que el bucle de eventos realice las llamadas necesarias en el código de la aplicación cuando los recursos están disponibles. Por ejemplo, un servidor en red abre los conectores y luego los registra para recibir avisos cuando eventos ocurren en ellos. El bucle de eventos alerta al código del servidor cuando hay una nueva conexión entrante o cuando hay datos para leer. Se espera que el código de la aplicación ceda el control nuevamente después de un corto período de tiempo cuando no se puede hacer más trabajo en el contexto actual. Por ejemplo, si no hay más datos para leer desde un conector el servidor debe devolver el control al bucle de eventos.
El mecanismo para devolver el control al bucle de eventos depende de las
co-rutinas Python, funciones especiales que ceden el control a la llamador
sin perder su estado. Las co-rutinas son similares a las funciones generador,
y de hecho los generadores pueden ser utilizados para implementar co-rutinas en
versiones de Python anteriores a 3.5 sin soporte nativo para objetos co-rutina.
asyncio
también proporciona una capa de abstracción basada en clases para
protocolos y transportes para escribir código utilizando funciones de
devolución de llamada en lugar de escribir directamente co-rutinas. Tanto en
el modelos basados en clases y co-rutinas, cambiar explícitamente el contexto
al volver a entrar al bucle de eventos reemplaza los cambios implícitos de
contexto la implementación de hilos de Python.
Un futuro es una estructura de datos que representa el resultado del trabajo
que aún no se ha completado. El bucle de eventos puede esperar que un objeto
Future
se configure como hecho, permitiendo que una parte de una aplicación
esperar a que otra parte termine un trabajo. Además de futuros, asyncio
incluye otras primitivas de concurrencia, tales como cerraduras y semáforos.
Una Task
es una subclase de Future
que sabe cómo envolver y gestionar
la ejecución de una co-rutina. Las tareas pueden ser programadas con el bucle
de eventos para ejecutarse cuando los recursos que necesitan estén disponibles,
y para producir un resultado que pueda ser consumido por otras co-rutinas.