Uso de async y await

Changelog

Nuevo en la versión 2.0.

Las rutas, los manejadores de errores, las funciones antes de la solicitud, después de la solicitud y el desmontaje pueden ser funciones coroutinas si Flask se instala con el extra async (pip install flask[async]). Esto permite definir las vistas con async def y utilizar await.

@app.route("/get-data")
async def get_data():
    data = await async_db_query(...)
    return jsonify(data)

Las vistas basadas en clases enchufables también admiten manejadores que se implementan como coroutines. Esto se aplica al método dispatch_request() en las vistas que heredan de la clase flask.views.View, así como a todos los manejadores de métodos HTTP en las vistas que heredan de la clase flask.views.MethodView.

Uso de async en Windows con Python 3.8

Python 3.8 tiene un error relacionado con asyncio en Windows. Si encuentras algo como ValueError: set_wakeup_fd only works in main thread, por favor actualiza a Python 3.9.

Uso de async con greenlet

Cuando se utiliza gevent o eventlet para servir una aplicación o parchear el tiempo de ejecución, se requiere greenlet>=1.0. Cuando se utiliza PyPy, se requiere PyPy>=7.3.7.

Rendimiento

Las funciones asíncronas requieren un bucle de eventos para ejecutarse. Flask, como aplicación WSGI, utiliza un trabajador para manejar un ciclo de solicitud/respuesta. Cuando una solicitud llega a una vista asíncrona, Flask iniciará un bucle de eventos en un hilo, ejecutará la función de la vista allí, y luego devolverá el resultado.

Cada solicitud sigue ocupando un trabajador, incluso para las vistas asíncronas. La ventaja es que puedes ejecutar código asíncrono dentro de una vista, por ejemplo para hacer múltiples consultas concurrentes a la base de datos, peticiones HTTP a una API externa, etc. Sin embargo, el número de peticiones que tu aplicación puede manejar al mismo tiempo seguirá siendo el mismo.

Async no es inherentemente más rápido que el código sync. Async es beneficioso cuando se realizan tareas concurrentes ligadas al IO, pero probablemente no mejorará las tareas ligadas a la CPU. Las vistas tradicionales de Flask seguirán siendo apropiadas para la mayoría de los casos de uso, pero el soporte asíncrono de Flask permite escribir y utilizar código que antes no era posible de forma nativa.

Tareas de fondo

Las funciones asíncronas se ejecutarán en un bucle de eventos hasta que se completen, momento en el que el bucle de eventos se detendrá. Esto significa que cualquier tarea adicional generada que no se haya completado cuando la función asíncrona finalice será cancelada. Por lo tanto, no puedes generar tareas en segundo plano, por ejemplo a través de asyncio.create_task.

Si desea utilizar tareas en segundo plano, es mejor utilizar una cola de tareas para activar el trabajo en segundo plano, en lugar de generar tareas en una función de vista. Teniendo esto en cuenta, puedes generar tareas asyncio sirviendo a Flask con un servidor ASGI y utilizando el adaptador asgiref WsgiToAsgi como se describe en ASGI. Esto funciona ya que el adaptador crea un bucle de eventos que se ejecuta continuamente.

Cuándo utilizar Quart en su lugar

El soporte asíncrono de Flask es menos eficiente que los frameworks asíncronos debido a la forma en que se implementa. Si tienes una base de código principalmente asíncrona tendría sentido considerar Quart. Quart es una reimplementación de Flask basada en el estándar ASGI en lugar de WSGI. Esto le permite manejar muchas peticiones concurrentes, peticiones de larga duración, y websockets sin requerir procesos de trabajo individuales o hilos.

También ha sido posible ejecutar Flask con Gevent o Eventlet para obtener muchos de los beneficios del manejo de peticiones asíncronas. Estas librerías parchean funciones de Python de bajo nivel para lograr esto, mientras que async/ await y ASGI utilizan capacidades estándar y modernas de Python. Decidir si debes usar Flask, Quart, o alguna otra cosa depende en última instancia de la comprensión de las necesidades específicas de tu proyecto.

Extensiones

Las extensiones de Flask anteriores al soporte asíncrono de Flask no esperan vistas asíncronas. Si proporcionan decoradores para añadir funcionalidad a las vistas, probablemente no funcionarán con las vistas asíncronas porque no esperarán la función o serán aguardables. Otras funciones que proporcionan tampoco serán aguardables y probablemente se bloquearán si se llaman dentro de una vista asíncrona.

Los autores de extensiones pueden soportar funciones asíncronas utilizando el método flask.Flask.ensure_sync(). Por ejemplo, si la extensión proporciona un decorador de función de vista, añada ensure_sync antes de llamar a la función decorada,

def extension(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        ...  # Extension logic
        return current_app.ensure_sync(func)(*args, **kwargs)

    return wrapper

Comprueba el registro de cambios de la extensión que quieres usar para ver si han implementado el soporte asíncrono, o haz una petición de funcionalidad o PR a ellos.

Otros bucles de eventos

Por el momento Flask sólo soporta asyncio. Es posible anular flask.Flask.ensure_sync() para cambiar la forma en que se envuelven las funciones asíncronas para utilizar una biblioteca diferente.