Использование async и await
Changelog
Новое в версии 2.0.
Маршруты, обработчики ошибок, функции перед запросом, после запроса и завершения могут быть функциями-генераторами, если Flask установлен с дополнительным компонентом async (pip install flask[async]). Это позволяет определять представления с async def и использовать await.
@app.route("/get-data")
async def get_data():
data = await async_db_query(...)
return jsonify(data)
Представления на основе классов с плагинами также поддерживают обработчики, реализованные как генераторы. Это относится к методу dispatch_request() в представлениях, наследующих от класса flask.views.View, а также ко всем обработчикам методов HTTP в представлениях, наследующих от класса flask.views.MethodView.
Использование async в Windows на Python 3.8
В Python 3.8 есть ошибка, связанная с asyncio в Windows. Если вы столкнетесь с чем-то вроде ValueError: set_wakeup_fd only works in main thread, обновитесь до Python 3.9.
Использование async с greenlet
При использовании gevent или eventlet для обслуживания приложения или изменения среды выполнения требуется greenlet>=1.0. При использовании PyPy требуется PyPy>=7.3.7.
Производительность
Функции async требуют наличия цикла событий. Flask, как WSGI-приложение, использует одного работника для обработки одного цикла запроса/ответа. При поступлении запроса в представление async Flask запустит цикл событий в потоке, выполнит функцию представления в этом потоке, а затем вернет результат.
Каждый запрос по-прежнему связывает одного работника, даже для представлений async. Преимущество состоит в том, что вы можете запускать асинхронный код в представлении, например, для выполнения нескольких одновременных запросов к базе данных, запросов HTTP к внешнему API и т. д. Однако количество запросов, которые может обрабатывать ваше приложение одновременно, останется прежним.
Асинхронный код не обязательно быстрее синхронного. Асинхронный код полезен при выполнении одновременных задач ввода-вывода, но, вероятно, не улучшит задачи, связанные с процессором. Традиционные представления Flask по-прежнему будут уместны для большинства случаев использования, но поддержка асинхронности Flask позволяет писать и использовать код, который ранее не был возможен.
Фоновые задачи
Асинхронные функции будут выполняться в цикле событий до завершения, после чего цикл событий остановится. Это означает, что любые дополнительные запущенные задачи, которые не завершились к моменту завершения асинхронной функции, будут отменены. Поэтому вы не можете запускать фоновые задачи, например, с помощью asyncio.create_task.
Если вы хотите использовать фоновые задачи, лучше использовать очередь задач для запуска фоновой работы, а не запускать задачи в функции представления. С этой целью вы можете запускать задачи asyncio, обслуживая Flask с сервером ASGI и используя адаптер asgiref WsgiToAsgi, как описано в ASGI. Это работает, так как адаптер создает цикл событий, который работает постоянно.
Когда использовать Quart вместо Flask
Поддержка асинхронности в Flask менее производительна, чем в фреймворках, ориентированных на асинхронность, из-за способа её реализации. Если у вас преимущественно асинхронный код, имеет смысл рассмотреть Quart. Quart — это повторная реализация Flask на основе стандарта ASGI вместо WSGI. Это позволяет ему обрабатывать множество одновременных запросов, длительные запросы и веб-сокеты без необходимости в нескольких процессах или потоках.
Также было возможно запустить Flask с Gevent или Eventlet, чтобы получить преимущества асинхронной обработки запросов. Эти библиотеки изменяют низкоуровневые функции Python для достижения этой цели, тогда как async/ await и ASGI используют стандартные современные возможности Python. Решение о том, использовать ли Flask, Quart или что-то другое, в конечном итоге зависит от понимания конкретных потребностей вашего проекта.
Расширения
Расширения Flask, созданные до поддержки асинхронности в Flask, не ожидают асинхронных представлений. Если они предоставляют декораторы для добавления функциональности в представления, они, вероятно, не будут работать с асинхронными представлениями, так как они не будут ожидать выполнение функции или быть ожидаемыми. Другие предоставляемые функции также не будут ожидаемыми и, скорее всего, будут блокирующими, если их вызвать внутри асинхронного представления.
Авторы расширений могут поддерживать асинхронные функции, используя метод flask.Flask.ensure_sync(). Например, если расширение предоставляет декоратор функции представления, добавьте ensure_sync перед вызовом декорированной функции.
def extension(func):
@wraps(func)
def wrapper(*args, **kwargs):
... # Extension logic
return current_app.ensure_sync(func)(*args, **kwargs)
return wrapper
Проверьте changelog расширения, которое вы хотите использовать, чтобы увидеть, реализована ли в нём поддержка асинхронности, или отправьте запрос на добавление функции или PR.
Другие циклы событий
В настоящее время Flask поддерживает только asyncio. Можно переопределить flask.Flask.ensure_sync(), чтобы изменить способ обертывания асинхронных функций для использования другой библиотеки.
© 2007–2022 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.2.x/async-await/