Использование async и await
Новое в версии 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)
Использование async в Windows на Python 3.8
В Python 3.8 есть ошибка, связанная с asyncio в Windows. Если вы столкнулись с чем-то вроде ValueError: set_wakeup_fd only works in main thread, обновитесь до Python 3.9.
Производительность
Асинхронные функции требуют для работы цикл событий. Flask как приложение WSGI использует одного работника для обработки одного цикла запроса/ответа. Когда запрос поступает в асинхронное представление, Flask запустит цикл событий в потоке, выполнит там функцию представления, а затем вернет результат.
Каждый запрос всё равно использует одного работника, даже для асинхронных представлений. Преимущество заключается в том, что вы можете запускать асинхронный код внутри представления, например, для выполнения нескольких одновременных запросов к базе данных, 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
Проверьте журнал изменений расширения, которое вы хотите использовать, чтобы узнать, реализована ли в нём поддержка асинхронных функций, или сделайте запрос на новую функцию или PR.
Другие циклы событий
В настоящее время Flask поддерживает только asyncio. Возможно переопределить flask.Flask.ensure_sync() для изменения способа обертывания асинхронных функций для использования другой библиотеки.
© 2007–2021 Pallets
Licensed under the BSD 3-clause License.
https://flask.palletsprojects.com/en/2.0.x/async-await/