На сегодняшний день асинхронное программирование имеет первостепенную важность в Python. Если вы являетесь веб-разработчиком, то у вас есть выбор между несколькими потрясающими фреймворками!
На момент написания этой статьи понятие «асинхронность» перестало быть просто «умным» словечком в сообществе Python. Выпустив версию 3.5 своей библиотеки asyncio, Python признал, что Node.js все же влияет на веб-разработку и добавил в язык два новых ключевых слова – async и await.
Это было очень важное событие, так как Python крайне осторожно относится к расширению базового синтаксиса, если только в этом нет острой необходимости. Это лишний раз показывает, что разработчики Python считали асинхронное программирование принципиально важным.
В результате для асинхронного программирования были открыты все пути: новые и старые библиотеки начали использовать возможности сопрограмм, популярность асинхронных фреймворков резко возросла, а новые продолжают создаваться и по сей день.
Производительность, сопоставимая и даже превосходящая производительность Node.js, не является чем-то баснословным, и если ваша нагрузка не включает в себя огромное количество задач, перегружающих ЦП, то почему бы вам не выполнять по несколько тысяч запросов в секунду.
Но хватит убеждений!
Давайте изучим текущую картину с Python и рассмотрим некоторые из лучших асинхронных фреймворков.
1. Tornado
На удивление, Tornado – вовсе не новый фреймворк. Он был выпущен еще в 2009 году, и с тех пор его основой задачей является обеспечение надежного асинхронного программирования с высоким уровнем параллелизма.
Tornado – это по сути не веб-фреймворк. Это набор асинхронных модулей, которые также используются для создания модулей веб-фреймворка, а именно:
- Сопрограммы и прочие примитивы (tornado.gen, tornado.locks, tornado.queues и т.д.)
- Сетевые модули (tornado.ioloop, tornado.iostream и т.д.)
- Асинхронные серверы и клиенты (tornado.httpserver, tornado.httpclient и т.д.)
Они объединены и создают конечные модули фреймворка: tornado.web, tornado.routing, tornado.template и т.д.
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Tornado имеет сильных и преданных сторонников в сообществе Python. Кроме того, его используют опытные разработчики архитектур для того, чтобы создавать высокопроизводительные системы. Это фреймворк, который уже давно дал отпор проблемам параллелизма, но, вполне возможно, так и не стал популярным, так как не поддерживает стандарт WSGI или из-за слишком большой личной заинтересованности (не забывайте, что большинство библиотек Python по-прежнему являются синхронными).
2. Sanic
Sanic – это в самом буквальном смысле слова «современный» фреймворк. Он не поддерживает Python версии ниже 3.6, но при этом поддерживает простой и универсальный синтаксис async/await, и, как следствие, не заставляет вас читать тонны документации и запоминать все пограничные случаи перед тем, как приступить к созданию своего первого HTTP-обработчика.
В итоге синтаксис получился весьма удобным (по крайней мере, я так считаю). Все равно что вы бы написали его с помощью любого другого микрофреймворка (например, Flask, CherryPy) и нескольких функций async:
from sanic import Sanic
from sanic.response import json
app = Sanic()
@app.route("/")
async def test(request):
return json({"hello": "world"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Sanic небезосновательно можно назвать самым популярным и любимым асинхронным фреймворком в мире Python. В нем есть практически все функции, необходимые для создания ваших проектов – маршрутизация, межплатформенное ПО, cookie-файлы, управление версиями, макеты, представления на основе классов, статические файлы, потоковая передача, сокеты и т.д. А поскольку на сегодняшний день существует немало асинхронных библиотек для этого фреймворка, в него можно добавить некоторые дополнительные вещи – шаблоны, поддержка баз данных, файловый ввод-вывод, очереди.
3. Vibora
Vibora – это «близкий родственник» Sanic, за исключением того, что он заточен под то, чтобы стать самым быстрым веб-сервером Python. Собственно, при первом посещении их сайта, вы сразу же наткнетесь на сравнение этих фреймворков:
Как видите, Vibora утверждает, что он в несколько раз быстрее, чем классические фреймворки и более чем в два раза быстрее, чем Sanic, который является его ближайшим конкурентом. Ясное дело, ко всему этому следует относится скептически.
Несмотря на то, что Vibora вполне соизмерима с Sanic с точки зрения синтаксиса и функций (или, может быть, даже превосходит, так как объединяет в себе популярные библиотеки и такие вещи, как готовые шаблоны), я все же считаю, что Sanic более развитый, так как давно существует и имеет большое сообщество.
from vibora import Vibora, JsonResponse
app = Vibora()
@app.route('/')
async def home():
return JsonResponse({'hello': 'world'})
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8000)
Если вы любитель высокой производительности, Vibora вам определенно угодит. Несмотря на это на момент написания статьи Vibora полностью переписывалась с целью стать еще быстрее, а ссылка на ее производительную версию гласила, что она находится в стадии «интенсивной разработки». Тех, кто начал использовать Vibora раньше всех, вскоре настигнет разочарование, ведь они столкнуться с серьезными изменениями, но, эй, асинхронный мир Python только зарождается, так что не стоит ждать, что все будет стабильно.
4. Quart
Если вам нравится работать с Flask, но при этом вам не хватает асинхронных функций, вас очень заинтересует Quart.
Quart придерживается стандарта ASGI, который стал заменой известного стандарта WSGI, и предлагает вашему вниманию поддержку асинхронности. Самое интересное в Quart то, что он не только похож на Flask, но и совместим с его API! Автор этого фреймворка хотел сохранить атмосферу Flask и просто добавить к нему поддержку асинхронности, WebSockets и HTTP/2. Таким образом, вы можете изучить Quart с помощью документации Flask, просто принимая во внимание тот факт, что функции в Quart асинхронные.
from quart import Quart
app = Quart(__name__)
@app.route('/')
async def hello():
return 'hello'
app.run()
Очень похоже (почти) на Flask, не так ли?
Так как Quart – это эволюционировавший Flask, в нем есть все функции Flask: маршрутизация, межплатформенное ПО, сеансы, шаблоны, макеты и т.д. По сути, вы даже можете использовать в нем расширения Flask. Единственная загвоздка в том, что он поддерживает Python версии 3.7 и выше, но если вы используете не последнюю версию Python, то, возможно, асинхронные функции не для вас.
Если вы никогда не работали с Flask, то документация вам просто необходима. Впрочем, я могу посоветовать вам Quart, так как это, пожалуй, единственный асинхронный фреймворк, который в скором времени выпустить версию 1.0.
5. FastAPI
Последний (но при этом самый впечатляющий) фреймворк в этом списке – FastAPI. Нет, это не фреймворк для создания API. По сути, FastAPI – это наиболее многофункциональная платформа, обладающая подробной документацией, с которой я познакомился в процессе исследования асинхронных фреймворков Python.
Любопытно, что автор фреймворка в деталях изучил несколько других фреймворков – от ультрасовременных по типу Django до обыкновенных по типу Sanic, а также изучил технологии NestJS (веб-фреймворк Node.js и TypeScript).
Синтаксис здесь довольно удобный. Можно даже сказать, что он гораздо удобнее, чем в других фреймворках, которые мы рассматривали:
rom fastapi import FastAPI
app = FastAPI()
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}
@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}
А теперь я хочу представить вашему вниманию список ключевых функций:
Автоматическая генерация документации API. Как только, ваши конечные точки будут написаны, вы можете поэкспериментировать с API, используя пользовательский интерфейс, соответствующий стандарту. Поддерживаются SwaggerUI, ReDoc и прочие.
Кроме того, платформа автоматически документирует модели данных с помощью схемы JSON.
Современная разработка. Да, понятие «современное» используется довольно часто, но я могу констатировать, что FastAPI действительно ему соответствует. Внедрение зависимостей и подсказки при вводе кода не просто обеспечивают соблюдение правильных принципов написания программного кода, но и предотвращают появление ошибок и путаницы.
Подробная документация. Не знаю как вы, но я обожаю хорошую документацию. И здесь FastAPI с легкостью всех обходит. Страница за страницей в ней описываются все мелочи, а также моменты, на которые стоит обратить внимание разработчикам всех уровней. В эту документацию вложили всю душу, и единственное сравнение, которое я могу привести, - это документация Django (да, документация FastAPI настолько хороша!).
Дополнительные функции. FastAPI поддерживает WebSockets, потоковую передачу, а также GraphQL. Помимо этого, об поддерживает все стандартные вспомогательные механизмы, такие как CORS, сеансы, cookie-файлы и т.д.
Так, а что насчет производительности? Что ж, в основе FastAPI лежит потрясающая библиотека Starlette, что обеспечивает производительность сравнимую с Node, а в некоторых случаях даже Go! В общем и целом, у меня есть стойкое ощущение, что FastAPI будет стремиться стать лучшим асинхронным фреймворком Python.
6. BlackSheep
BlackSheep можно использовать для создания серверных и полнофункциональных приложений на базе шаблона MVC.
Вот некоторые из функций, которые предлагает BlackSheep:
- API с «богатым» кодом.
- Встроенное внедрение зависимостей.
- Встроенное создание документации OpenAPI.
- Автоматическая привязка обработчиков событий.
Настройка проекта
Давайте создадим простое серверное приложение с помощью BlackSheep. Чтобы настроить проект, запустите команды, приведенные ниже, одну за другой.
python -m venv basic-app
cd basic-app
source bin/activate
pip install blacksheep uvicorn
Настройка проекта завершена. Давайте создадим файл с именем server.py и поместим в него следующий код.
from blacksheep import Application
app = Application()
@app.router.get("/")
def home():
return "Hello, World!"
Мы создали самое известное приложение «Hello, World!». На данный момент существует только один маршрут с методом HTTP GET и параметром /. Функция home в BlackSheep называется обработчиком запросов.
Мы использовали декоратор router из класса app. Помимо этого, существует еще один способ создать маршрут - route. В данном случае мы будем использовать router. Более подробную информацию о route вы можете найти в документации.
Давайте запустим приложение с помощью следующей команды:
uvicorn server:app --port 8000 --reload
Перейдем по следующему адресу в браузере: http://localhost:8000/. Вы увидите там надпись «Hello, World!». Давайте немного поговорим о команде, которую мы использовали для запуска приложения.
- Для запуска нашего приложения мы использовали пакет uvicorn.
- server - это имя файла, которые мы указали сами. Если вы используете другое имя файла, измените его в команде запуска.
- Флаг --port указывает порт, где будет работать наше приложение.
- И наконец, флаг --reload позволяет перезагружать приложение в браузере всякий раз, когда мы вносим изменения в файл server.
JSON-ответ
В реальных условиях в большинстве случаев нам требуется ответ API в формате JSON. Мы можем его получить из метода, упаковав объект JSON в json из пакета blacksheep. Давайте посмотрим, как мы можем это сделать.
from blacksheep import Application, json
app = Application()
@app.router.get("/")
def home():
return json({"message": "Hello, World!"})
Мы можем импортировать json из blacksheep и упаковать с его помощью объект JSON. Проверьте этот код в браузере на наличие JSON-ответа.
Параметры маршрутизации
Иногда нам необходимо принимать параметры маршрутизации для запросов. Мы можем сделать это в BlackSheep, определив их внутри метода HTTP. Давайте посмотрим, как это работает.
@app.router.get("/{name}")
def home(name):
return json({"greetings": f"Hello, {name}!"})
Мы принимаем один параметр маршрутизации под названием name. Переходим по адресу http://localhost:8000/Geekflare. Метод вернет нам приветствие с именем, указанном в маршруте.
Декоратор router передает в функцию home параметр с тем же именем, что и параметр, который был передан ему. В данном случае это name. Если вы измените его в декораторе, его необходимо изменить и в функции home.
Аналогично мы можем принять и большее количество параметров. Давайте посмотрим на небольшой пример.
@app.router.get("/{name}/{info}")
def home(name, info):
return json({"greetings": f"Hello, {name}! Info {info}"})
Мы приняли еще один параметр маршрутизации под названием info. переходим по адресу http://localhost:8000/Geekflare/Chandan и проверяем.
Параметры запросов
Для того, чтобы принять параметры запроса, нам не нужно предпринимать каких-то дополнительных действий. BlackSheep автоматически отправляет функции параметры запроса в виде списка. Давайте рассмотрим пример.
@app.router.get("/")
def home(name):
print(name)
return json({"greetings": f"Hello, {name[0]}!"})
Перейдем по адресу http://localhost:8000/?name=Geekflare и проверим ответ. Если у вас есть несколько параметров запросов с одинаковыми именами, BlackSheep добавит в список все.
Перейдем по адресу http://localhost:8000/?name=Geekflare&name=Chandan и проверим вывод в терминале. Вы увидите список из двух параметров: Geekflare и Chadan, так как мы передали два параметра запросов с одинаковыми именами.
Если вам нужно передать несколько параметров с разными именами, вы также можете это сделать. Просто добавьте в функцию еще один аргумент с именем параметра и делайте с ним все, что посчитаете нужным.
Объект-запрос
Единственное, что осталось из основных вещей, - это проверка других методов HTTP. Прежде чем более подробно рассмотреть все это, давайте проверим объект request на наличие API.
Все обработчики запросов в BlackSheep буду иметь аргумент request, который содержит всю информацию о входящем запросе. Туда входят заголовки запросов, параметры пути, параметры запроса, данные и т.д.
Давайте посмотрим пример, чтобы увидеть, как это работает.
@app.router.post("/")
def home(request):
print(request)
return "Hello, World!"
В терминале вы увидите следующее:
<Request POST />
Мы можем получить доступ к различным вещам из запроса. Мы можем проверить документацию. В таком случае наше внимание должно быть сосредоточено на теле запроса. Давайте посмотрим, как получить доступ к телу запроса из объекта request.
@app.router.post("/")
async def home(request):
data = await request.json()
print(data)
return "Hello, World!"
В запросе присутствует метод json, который возвращает данные, полученные из запроса. Передайте ему некоторые данные в запросе API и вызовите его. Вы увидите, что в терминале выводятся данные, которые вы передали API.
HTTP-методы
В примере выше мы рассмотрели методы GET и POST. Точно так же вы можете использовать методы PUT, DELETE и т.д. Они довольно простые, так что воспользоваться ими не составит труда.
7. AIOHTTP
aiohttp – это еще один фреймворк. Вот его основные функции:
- Он поддерживает WebSockets как стороне сервера, так и на стороне клиента.
- Он поддерживает разработку как серверных, так и клиентских приложений.
- Его веб-сервер обладает межплатформенным ПО, сигналами и подключаемой маршрутизацией.
Настройка проекта
Давайте создадим простое серверное приложение с помощью aiohttp. Чтобы настроить проект, запустите следующие команды:
python -m venv basic-app
cd basic-app
source bin/activate
pip install aiohttp aiodns
Создаем файл server.py и помещаем в него следующий код:
from aiohttp import web
async def home(request):
return web.Response(text="Hello, World!")
app = web.Application()
app.add_routes([web.get('/', home)])
web.run_app(app)
Экземпляр web.Application - это наше основное приложение. Мы добавили метод HTTP GET с маршрутом /, который возвращает всеми любимый «Hello, World!». Функция web.run_app используется для запуска приложения и принимает в качестве аргумента экземпляр web.Application.
Функция home в aiohttp называется обработчиком запросов. У него есть один единственный аргумент под названием request, который содержит всю информацию о входящем запросе.
Запустим приложение с помощью следующей команды. Это все равно что запустить обычную программу на Python.
python3 server.py
Перейдем в браузере по следующему адресу: http://localhost:8080/, и вы увидите там надпись «Hello, World!».
JSON-ответ
Мы можем получить ответ в формате JSON, воспользовавшись функцией web.json_response. Передадим в нее данные JSON и вернем ответ. Давайте посмотрим пример.
async def home(request):
return web.json_response({"message": "Hello, World!"})
Если вы перейдете по адресу http://localhost:8080/, то увидите в браузере объект JSON.
Параметры маршрутизации
Мы можем определить параметры маршрутизации при непосредственном добавлении маршрутов. Доступ к ним можно получить из аргумента request обработчика запроса. Давайте посмотрим на пример.
from aiohttp import web
async def home(request):
return web.json_response({"message": f"Hello, {request.match_info['name']}!"})
app = web.Application()
app.add_routes([web.get('/{name}', home)])
web.run_app(app)
Доступ ко всем параметрам можно получить с помощью request.match_info (см. пример выше). Перейдем по адресу http://localhost:8080/Geekflare и проверим это.
Кроме того, для составления маршрутов мы можем использовать регулярные выражения. Допустим, нам нужно принять только /{any_number}. В таком случае мы можем сделать это, заменив '/{name}' на r'/{number:\d+}'. Мы добавили к параметру маршрутизации параметр пути, который будет приниматься только тогда, когда это регулярное выражение будет передано.
Давайте посмотрим пример.
from aiohttp import web
async def home(request):
return web.json_response({"message": f"Hello, {request.match_info['number']}!"})
app = web.Application()
app.add_routes([web.get(r'/{number:\d+}', home)])
web.run_app(app)
Перейдем по адресу http://localhost:8080/Geekflare и увидим ошибку 404, так как Geekflare не соответствует шаблону регулярного выражения, который мы указали. А теперь перейдите по этому адресу: http://localhost:8080/1234567890, и вы увидите в браузере ответ.
Параметры запроса
Для того, чтобы принять параметры запроса, не нужно ничего добавлять. Мы можем принять параметры запроса из объекта request.query. Давайте посмотрим на пример.
from aiohttp import web
async def home(request):
return web.json_response({"message": f"Hello, {request.query.get('name')}"})
app = web.Application()
app.add_routes([web.get('/', home)])
web.run_app(app)
Перейдем по адресу http://localhost:8080/?name=Geekflare и проверим результат. Вы увидите, что в ответе присутствует Geekflare, который вы приняли из request.query.
Мы можем передавать несколько параметров, к которым можно получить доступ по их именам.
HTTP-методы
В примерах, приведенных выше, мы видели, как создается метод HTTP GET. Прежде чем, мы пойдем дальше, нам нужно разобраться, как получить доступ к данным запроса. Давайте посмотрим пример.
from aiohttp import web
async def home(request):
data = await request.json()
print(data)
return web.json_response({"message": f"Hello, World!"})
app = web.Application()
app.add_routes([web.post('/', home)])
web.run_app(app)
В этом примере мы изменили метод API с GET на POST. А доступ к данным запроса мы получили с помощью метода request.json.
Отправьте запрос POST на http://localhost:8080/, и вы увидите, как в терминале напечатаются данные запроса.
Аналогично вы можете использовать методы PUT, DELETE и т.д. Попробуйте сделать то сами.
Более подробную информацию о фреймворке вы можете найти в его документации.
8. Falcon
Falcon – это фреймворк для создания REST API и микрослужб, придерживающийся стандарта ASGI. Вот его основные функции:
- Он поддерживает WebSockets.
- Поддерживает межплатформенное ПО и перехватчиков для обработки запросов.
- Простая и понятная обработка исключений.
Настройка проекта
Чтобы изучить основы Falcon, давайте создадим проект и настроим его с помощью следующих команд:
python -m venv basic-app
cd basic-app
source bin/activate
pip install falcon uvicorn
Создадим файл server.py и добавим в него следующий код:
from falcon import asgi
import falcon
class Home:
async def on_get(self, request, response):
response.status = falcon.HTTP_200 # This is the default status
response.content_type = falcon.MEDIA_TEXT # Default is JSON, so override
response.text = 'Hello, World!'
app = asgi.App()
app.add_route('/', Home())
Мы создали класс с методом on_get, который является методом HTTP GET. Метод может принимать два аргумента. Первый – запрос (request), а второй – ответ (response) (не сложно догадаться по их названиям).
Аргумент request содержит всю информацию о входящем запросе, к которой мы можем получить доступ для того, чтобы обработать этот запрос. Аргумент response нужен для того, чтобы настраивать различные параметры для отправки ответа.
В отличие от BlackSheep и AIOHTTP, нам не нужно возвращать ответ. Мы можем воспользоваться аргументом response и настроить любые детали, которые мы хотим отправить в качестве ответа. В примере выше мы установили следующее: статус – 200, содержимое - текст, текст – «Hello, World!».
Запустим приложение с помощью следующей команды:
uvicorn server:app --reload
Перейдем по адресу http://localhost:8000/ и увидим, что в качестве ответа выводится «Hello, World!».
JSON-ответ
Мы можем вернуть ответ в формате JSON, преобразовав данные в JSON с помощью метода json.dumps. Давайте посмотрим пример.
from falcon import asgi
import falcon
import json
class Home:
async def on_get(self, request, response):
response.text = json.dumps({"greetings": "Hello, World!"})
app = asgi.App()
app.add_route('/', Home())
Перейдем по адресу http://localhost:8000/ и увидим ответ в формате JSON.
Параметры маршрутизации
Параметры маршрутизации передаются в качестве аргументов методам HTTP. Чтобы было более понятно, взглянем на пример ниже.
from falcon import asgi
import falcon
import json
class Home:
async def on_get(self, request, response, name):
response.text = json.dumps({"greetings": f"Hello, {name}!"})
app = asgi.App()
app.add_route('/{name}/', Home())
Параметр пути name передается в качестве аргумента методу on_get. Перейдем по адресу http://localhost:8000/Geekflare/ и проверим ответ. Параметров маршрутизации может быть несколько.
Параметры запроса
Мы можем получить доступ к параметрам запроса с помощью метода request.get_param(param_name). Изучим пример ниже.
from falcon import asgi
import falcon
import json
class Home:
async def on_get(self, request, response):
response.text = json.dumps({"greetings": f"Hello, {request.get_param('name')}!"})
app = asgi.App()
app.add_route('/', Home())
Перейдем по адресу http://localhost:8000/?name=Geekflare и проверим ответ. Параметров запроса может быть несколько.
HTTP-методы
В примере выше мы наблюдали метод GET. Единственное, что нам нужно знать, чтобы использовать другие методы, - это то, как получить доступ к данным запроса. Мы можем это сделать с помощью метода request.stream.read. Давайте посмотрим пример.
from falcon import asgi
import falcon
import json
class Home:
async def on_get(self, request, response):
response.text = json.dumps({"greetings": "Hello, World!"})
async def on_post(self, request, response):
data = await request.stream.read()
print(json.loads(data))
response.text = "Hello, World!"
app = asgi.App()
app.add_route('/', Home())
Мы добавили один метод POST, в котором мы получили доступ к данным запроса и после того, как преобразовали их в JSON, распечатали в терминале. Выполните запрос POST с несколькими данными и проверьте результат.
Попробуйте самостоятельно добавить другие методы HTTP, например, DELETE, PUT и т.д. Мы охватили только основы фреймворка Falcon. Но в нем есть еще много чего интересного. Чтобы узнать о нем больше, изучите его документацию.
9. Starlette
Starlette – это легкий фреймворк, придерживающийся стандарта ASGI. Он оснащен практически всеми основными функциями, необходимыми для создания серверных приложений.
Запустите следующие команды и настройте проект:
python -m venv basic-app
cd basic-app
source bin/activate
pip install starlette uvicorn
Процесс создания API с помощью Starlette похож на то, что мы видели, рассматривая предыдущие фреймворки. Отличается только синтаксис и способ создания API, принципы остаются прежними. Итак, мы хотим добавить все в одну программу.
Создаем файл server.py и добавляем туда следующий код:
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse, JSONResponse
from starlette.routing import Route
def homepage(request):
return PlainTextResponse('Hello, World!')
def json_response(request):
return JSONResponse({'message': 'Hello, World!'})
def path_params(request):
name = request.path_params['name']
return JSONResponse({'greetings': f'Hello, {name}!'})
def query_params(request):
name = request.query_params['name']
return JSONResponse({'greetings': f'Hello, {name}!'})
async def post_method(request):
data = await request.json()
print(data)
return JSONResponse({'message': f'Hello, World!'})
def startup():
print('Starlette started')
routes = [
Route('/', homepage),
Route('/json', json_response),
Route('/path-params/{name}', path_params),
Route('/query-params', query_params),
Route('/post', post_method, methods=['POST']),
]
app = Starlette(debug=True, routes=routes, on_startup=[startup])
Запускаем приложение с помощью следующей команды:
uvicorn server:app --reload
Проверяем все, что мы видели в предыдущих фреймворках. Больше информации вы можете найти к документации Starlette.
Заключение
Сегодня в асинхронной среде Python происходит огромное количество событий. Появляются новые фреймворки, переписываются старые, развиваются библиотеки, чтобы соответствовать асинхронному принципу поведения. Несмотря на то, что Python имеет встроенную поддержку цикла событий, и вы вполне можете сделать части вашего приложения асинхронными, вы также можете пойти ва-банк и воспользоваться одним из фреймворков, описанных здесь.
Просто не забывайте о долгосрочной перспективе: некоторые из существующих асинхронных фреймворков Python находятся на ранних стадиях разработки и довольно быстро развиваются, что может навредить вашему процессу разработки и увеличить затраты.
Ключевым моментом здесь является осторожность!
Но несмотря на все сказанное и сделанное, когда дело касается веб-фреймворков, Python готов к тому, чтобы обеспечивать высочайший уровень производительности. Если вы уже давно думали о переходе на Node, то теперь вам это точно не нужно!