Comments 26
Скоро всем питоном на раст переедем )))))
Хорошо, что Python веб-приложения становятся быстрее. Конечно до Drogon на C++ ещё далеко, но это Python. Ну и конечно Drogon это фреймворк с веб-сервером, а не отдельный веб-сервер. Пока нагрузка небольшая на сервер, то по большому счёту нет сильной разницы какой асинхронный веб-фреймворк использовать. Разница начинается на больших нагрузках.
Ради интереса, перед написанием статьи я решил попробовать его в работе с Django.
Так и чем всё закончилось? Стало быстрее? А что быстрее?
Не очень понятно что должно измениться в случае WSGI-приложения. Шаблоны рендериться будут с такой же скоростью, да и интерпретатор питона будет тот же самый.
Улучшился отклик сайта, и в перспективе он будет обрабатывать большое количество запросов лучше и стабильнее чем uWSGI
Простите, но это ответ из серии "дерево справа более зелёное, чем слева".
Что значит "улучшился"? За счёт чего? У вас в обоих случаях за RSGI/WSGI фронтендом стоит питоновское приложение, одно и то же. И интерпретатор один и тот же. Однопоточный. В случае gunicorn фактически воркер и приложение работают в одном процессе. В RSGI, как я понимаю, бинарник на Rust вызывает Python-код, это уже некоторые накладные расходы. В любом случае, 98% времени будет выполняться именно Python-код джанги и приложения, а здесь выигрыша никакого не предвидится.
Разница WSGI и ASGI хотя бы понятна из-за чего. Здесь хотелось бы либо объяснения, либо результатов с тестами.
Опять же, перед всем этим в любом случае будет стоять балансер типа nginx, который возьмёт на себя основные расходы типа терминирования TLS и медленных клиентов.
RSGI не применяется в джанге, это отмечено в статье. Granian работает по WSGI, однако, даже в работе синхронно он обеспечивает производительность сопоставимую с ASGI. После реверс прокси идёт именно веб-сервер, у него есть свои задержки выполнения, это сравнение также есть в статье. Если брать значения "в лоб", у granian в шесть раз лучше показать задержки выполнения, а затем уже да, идёт джанга. И вот этого достаточно, чтобы повысить отзывчивость сайта. Преимущества в RPS проявят себя со временем при росте посещаемости. Gunicorn'а у меня никогда не было, я сразу использовал uWSGI и заменил его на Granian, вместо обвзяки Django Cannels + uvicorn.
Было-бы интересно увидеть статью как автор встраивает RSGI в своё веб-приложение, посмотреть нагрузку в его приложении и услышать его личный отзыв от использования.
Синхронный интерфейс взаимодействия — обрабатывает запросы один за другим.
Из первого не следует второе — к WSGI вполне прикручивают потоки или гринлеты (о чём вы сами же потом пишете ниже)
Не поддерживает ... SSE (Server-Sent Events)
SSE — это всего лишь один из вариантов streaming response, который прекрасно делается через WSGI (другое дело, что он будет занимать собой воркер, поэтому делать так обычно не очень разумно)
Синхронный и асинхронный интерфейс взаимодействия — может обрабатывать множество запросов одновременно.
Из первого не следует второе — стандартный event loop в питоне принципиально однопоточный, поэтому, если не обмазываться костылями вроде воркеров или стороннего пула потоков, запросы будут обрабатываться конкурентно, но не одновременно
может применяться в Django (через Channels)
Django уже давно поддерживает ASGI нативно без Channels (единственный мой пост как раз об этом)
Работает по схеме prefork (несколько процессов-воркеров).
То есть для uWSGI вы гринлеты упомянули, а gunicorn, у которого буквально слово green в названии, почему-то решили обидеть
сторонние классы воркеров (gevent/eventlet)
Они не сторонние
Производительность: несколько лучше, чем у Gunicorn в бенчмарках
А вот этот бенчмарк говорит, что uWSGI самый медленный (впрочем, насколько можно верить бенчмарку девятилетней давности, не знаю — но мне до сих пор интересно, что не так с этим бенчмарком)
А вот этот бенчмарк говорит, что uWSGI самый медленный (впрочем, насколько можно верить бенчмарку девятилетней давности, не знаю — но мне до сих пор интересно, что не так с этим бенчмарком)
впрочем, насколько можно верить бенчмарку девятилетней давности, не знаю
Я больше доверяю вот этой табличке:

Ссылка на первоисточник: https://www.techempower.com/benchmarks/#section=test&runid=3ab00ae1-17aa-44e6-ae83-137d797d0817&test=json&l=zik0zj-cn2&w=oedrsv-v2qiv3-zik0zj-zik0tr&a=2
granian - это конечно прикольно, но если с uvicorn вы можете запустить его из асинк функции (проведя нужную инициализацию) с помощью server.serve(). То с гранианом так уже не получится, он сам гоняет свой луп и никак иначе (по крайней мере среди стабильного апи)
RSGI в целом протокол странный. Описание очень скудное и такое ощущение что никто не задумывался об альтернативных реализациях.
Granian также можно вызывать из кода:
https://github.com/emmett-framework/granian?tab=readme-ov-file#embedding-granian-in-your-project
Про RSGI не могу ничего сказать. Он ещё очень молод, поэтому и скуден. Интересно будет наблюдать за его развитием, как со стороны применения в Python, так и в самом Rust
Основные выводы:
ASGI-серверы значительно превосходят WSGI по производительности
Вывод неверный.
ASGI-серверы быстрее при асинхронном выполнении запроса (БД и т.п.).
В полностью синхронных запросах WSGI протокол быстрее, т.к. проектировали ASGI протокол "странные" люди.
Вот пруфы:


Можно заметить, что на второй картинке вообще нету WSGI-движков, т.к. wsgi просто бесполезен при запросах к БД.
Granian показывает лучшие результаты как по скорости, так и по потреблению памяти
Для этого вывода нужна выборка по более. А у вас она маленькая.
Лучшие результаты смотрите тут: https://www.techempower.com/benchmarks/#section=test&runid=3ab00ae1-17aa-44e6-ae83-137d797d0817&l=zik0zj-cn2
Granian:
ASGI: ~0.7-1.2 мс (средняя задержка).
WSGI: ~1.5-2.5 мс (средняя задержка).
Вывод по задержкам: Даже в WSGI-режиме Granian превосходит традиционные серверы по этой метрике.
У вас какие-то странные результаты тестирования. Почти всегда у ASGI-серверов задержка больше, чем у WSGI.
И это подтверждается вот этой картинкой:

Явно видно, что все ASGI проигрывают WSGI.
Примечание: именно ради низких задержек я юзаю fastwsgi (и почти весь его переписал)
А не подскажете, какие настройки пула соединекний с БД были в тестах multiple queries? Я вижу, что конкаренси на HTTP запроса - 512, но сколько у нас пул в сервере с базой и сколько у нас пул воркеров - непонятно.
Судя по тому что я вижу, настройки очень разные везде. Например для fastapi - MAX_POOL_SIZE = 1000//multiprocessing.cpu_count() https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/frameworks/Python/fastapi/app_orm.py
А для фласк число воркеров - cput_count*2.5 https://github.com/TechEmpower/FrameworkBenchmarks/blob/master/frameworks/Python/flask/gunicorn_conf.py
Вообще не удивительно, что если они запускают 20 процессов обрабатывающий запросы по одному (ждущих ответа БД в каждом), что они медленнее чем 1000 корутин одновременно ждущих ответа БД. А таких условиях конечно wsgi будет медленнее asgi
В идеале, размер пула и количество воркеров должны подбираться исходя из конкретного приложения чтобы максимально эффективно утилизировать. Никому не интересно, что криво настроенное одно приложение работает медленее чем хорошо настроенное другое. Надо сравнивать два хорошо настроенных в одинаковых условиях эксплуатации.
Надо сравнивать два хорошо настроенных в одинаковых условиях эксплуатации.
Условия одинаковые. Настраивают сами авторы движков (в редких случаях умельцы).
Не знал. Правильно ли я понимаю, что в таком случае умельцу надо где-то раздобыть эквивалентое окружение (56 ядер и всё такое прочее) или они предоставляют возможность попробовать разные варианты настроек и выбрать лучшее? Условно, если я кину PR где увеличиваю число воркеров для фласка - как/когда я пойму как изменился результат теста?
Ну зачем же. Я у себя локально этот бенч и не разворачивал. Просто добавил PR для fastwsgi и blacksheep - эти движки теперь в репо.
Сначала нужно подождать добавления PR (обычно не более 7 дней). Затем дождаться окончания текущей задачи бенча и след. задачи, в которую уже обязан попасть ваш PR/commit.
Отслеживать можно тут: https://tfb-status.techempower.com/
Ну вопрос же в том чтобы подобрать правильные параметры. Условно, чтобы понять сколько надо воркеров и размер пула, может понадобиться сотня экспериментов с замером производительности. Как их проводить?
Мне в руки даже железка попадала на 99% такая же, которая все эти бенчи выполняет (только сетевушка была не на 40, а на 25). И даже там я не стал разворачивать полноценный репо FrameworkBenchmarks. Просто отдельно потестил на нём несколько движков.
Вот гляньте на показатели fastwsgi - он в топе в каждом типе бенча. А я просто при формировании PR указал такие же параметры, как и у других движков.
Автор granian недавно сделал изменение:
https://github.com/TechEmpower/FrameworkBenchmarks/commit/3c18f02c4c6e1a323b98bd78c5258297dadc4b9a
Поэтому: либо 2, либо 4
сколько у нас пул воркеров - непонятно.
Потоков там 56 (пруф: https://github.com/TechEmpower/FrameworkBenchmarks/issues/8736#issuecomment-1973835104 )
Обзор WSGI, ASGI и RSGI: лидеры среди веб-серверов в 2025 году