Комментарии 51
Господи, это же треш, а не сравнение. Почему кстати автор не сравнивает один к одному? Что за магические значения 5 и 16?
Оптимальное количество воркеров у асинхронных и синхронных фреймворков различается. У этого есть очевидные причины.
Эм… нет
Почему в разных конфигурациях используется разное количество воркеров?
Для того чтобы определить оптимальное количество процессов-воркеров, я пользовался одной и той же простой методикой. А именно, я, исследуя каждую из конфигураций, начинал с одного воркера. Потом я последовательно увеличивал их количество до тех пор, пока производительность конфигурации не ухудшалась.
Эта его методика никуда не годится. Человек сравнил теплое с мягким на основе каких-то субъективных метрик.
Почему? Человек нашёл максимум производительности в зависимости от количества воркеров. Что не так?
Максимум производительности чего?
Эта методика — чистый подгон под результат. Да, для этого конкретного бессмысленного синтетического теста были найдены оптимальные значения количества воркеров. Если бы эти значения были универсальными — они были бы — сюрприз! — дефолтными и захардкоженными.
Это все равно, что решать задачу нахождения числа Фибоначчи — доставанием значения из предварительно подготовленного словаря. O(1)
, прикиньте.
Кроме того, выполнение атомарных быстрых запросов (испорченных обращением в базу, правда, которая тоже не резиновая, но ладно, простим; на общем фоне это выглядит просто как досадная оплошность) — нивелирует всю ценность асинхронности, потому что в таком сценарии сами воркеры параллелятся.
Достаточно запустить N тяжелых запросов и следом один легкий на машине с N ядрами, и всем все сразу станет понятно. Ну или бессмертных вебсокетов эдак тысяч сто, и вперед.
Максимум производительности приложения, написанного с помощью указанных фреймворков на текущей конфигурации сервера.
А если без шуток, то:
— Асинхронщина не только для быстродействия нужна.
— Не увидел в статье информации про количество соединений от воркера к pgbouncer, что сразу ставит под вопрос объективность тестирования.
- Профиль нагрузки на сервер.
Нет, серьёзно, когда приложение лезет в БД, результаты бенчмарков сильно меняются
Ну как бы предсказуемо. Особенно предсказуемо если ты понимаешь что asyncio — это кооперативный event loop.
Ну и как бы в каждой нормальной статье или туториале по asyncio в самом начале пишут, для чего он был придуман.
Предлагаю автору повторить замеры но с измененным профилем нагрузки — не менее 10к долгоживущих HTTP/WebSocket соединений на воркера. Ну или в современных условиях можно и по 100к на воркера. И тогда посмотрим кто кого =)
Из анналов Stack Overflow:
if io_bound:
if io_very_slow:
print("Use Asyncio")
else:
print("Use Threads")
else:
print("Multi Processing")
Хотелось бы увидеть код бенчмарков.
Статья попахивает провокацией. Не объяснена объективность количества воркеров, а так же принцип выбора библиотек для Postgres. И к чему тут вообще Postgres если вроде как измеряем производительность web-фреймворков? Почему бы не замерить скорость ответа для статичной html страницы? Или замерить производительность для файлов > 10мб? Вопросов больше чем ответов
Так он не захардкоживал. Он нашёл оптимальные значения, просто результаты для неоптимальных выкинул.
Пожалуй, объясню почему я написал про один к одному :) Я читал статью за неделю до того как она на хабре появилась и мне казалось, что вполне очевидно, что с ней не так.
Про "один к одному" за который в меня только ленивый здесь пальцем не ткнул. Заголовок поста "Асинхронный Python-код медленнее обычного кода" — и тут в общем-то сложно спорить. Можно написать что-то одинаковое и без какого-либо сетевого взаимодействия сравнить лоб в лоб. И мы выясним что и вправду три мешка картошки тяжелее чем один. Тут даже питон не надо знать чтоб понимать, что тест отработает так как написано в заголовке.
Но когда в тесте появляются запросы к БД и сам тест это HTTP-сервис, то в общем-то производительность всего теста становится зависимой не только от кода. Да и в общем-то, накинуть тяжелых запросов, и каких-нибудь постоянных соединений и все будет совсем не так однозначно.
То есть я к тому, что такой тест вообще, не должен иметь права на жизнь, а больше похож на непонимание того, что и как готовить надо. И тут не важно сколько инстансов ко скольки если брешь в самой методике. Сравнивается то, что так просто нельзя сравнивать. Да и вополне очевидно, что можно написать такой тест на котором асинкайо будет в невыгодном свете ровно как и наоборот.
В статье про измерение производительности нет ни слова про измерение производительности. Идешь в предоставленный код — видишь там ab. Окей, действительно, никто тут производительность и не измерял.
Вот, например, результаты бенчмарка, созданного в рамках проекта Vibora (я этот фреймворк не тестировал, так как он относится к числу наименее популярных решений).
я бы сказал к числу мертвых. ведь в репозитории последний коммит был 17 месяцев назад(и то, редактировался readme. код же не обновлялся два года).
Чтобы асинхронный код был производительнее синхронного, необходимо под это настроить с-но инрфраструктуру. В данном конкретном случае, по сути, измеряется производительность базы данных.
Реплицируйте базу данных на 10 серверов. Используйте кеш. Думаю результаты будут значительно отличаться от текущих.
Про репликацию базы согласен, а вот как кэш поможет в случае именно асинка — я не понял.
Я воспринимаю этот бенчмарк как попытку показать, что типичные бенчмарки асинхронных фреймворков и есть "соревнования по безодорожью" как вы выразились. К сожалению, многие популярные бенчмарки как раз не учитывают что синхронный фреймворк нельзя гонять в одном воркере или что база не потянет 100000 одновременных коннектов-транзакций.
В этом плане этот тест как раз заставляет задуматься о реальном профиле нагрузке и необходимости настройки текущей инфраструктуры, вместо того чтобы бросаться переписывать все на asyncio в надежде получить профит из ничего
В этом плане этот тест как раз заставляет задуматься о реальном профиле нагрузке и необходимости настройки текущей инфраструктуры, вместо того чтобы бросаться переписывать все на asyncio в надежде получить профит из ничего
Тут и спорить не о чем. Каждый инструмент нужен для определенных вещей. Естественно нет смысла переписывать и даже писать с нуля сайтик, генерирующий 3 страницы в минуту с использованием ассинхронщины.
Почему тогда одна и та же БД с синхронным фронтендом работает быстрее?
Psycopg can issue asynchronous queries to a PostgreSQL database. An asynchronous communication style is established passing the parameter async=1 to the connect() function: the returned connection will work in asynchronous mode.
Это цитата из документации psycopg2
Судя по тому, что я вижу в коде, этот драйвер вообще работает в синхронном режиме. Причем это не изменяется и для ассинхронщины. С-но цикл событий блокируется при запросе к бд. И все преимущество сводиться на нет.
pool = psycopg2.pool.SimpleConnectionPool(
1, 4, database="test", user="test", password="test", port=6432,
)
А должно быть для ассинхронного кода
pool = psycopg2.pool.SimpleConnectionPool(
1, 4, database="test", user="test", password="test", port=6432, async=1
)
Предлагаю автору запустить рядом с каждым бенчмарком slowhttptest, чтобы понять, почему запускать неасинхронный код в 2020 очень глупо. Спойлер: rps упадет примерно до нуля. И это будет более реально отражать жизнь, т.к. настоящие клиенты где-то на другой стороне довольно медленной сети.
Настоящие клиенты обращаются к nginx, который берёт на себя всю «медленную» работу вместе с буферизацией всего подряд, а к питон-серверу приходит быстрый запрос от 127.0.0.1 или вообще по UNIX-сокету
Слишком много "но" и ограничений, при которых эта схема работает. Например, сразу можно забыть о больших post-запросах, websocket, и многом другом, что не умещается в один буфер. И это если мы вообще говорим о HTTP, вне которого все еще хуже. Можно бесконечно затыкать все эти дыры костялями и различными параметрами в nginx там, где это возможно, а можно просто писать нормальный асинхронный код и не париться.
Дополнительно, если так получается, что неасинхронный код нужно обязательно выкладывать в продакшон под защитой nginx, то и бенчмарки нужно делать с nginx. Тогда как для асинхронных приложений его можно опустить (и использовать более простые и более производительные штуки).
Во-первых, все перечисленные проблемы в nginx решаются (и это вообще не проблемы), а во-вторых, плюшек от nginx НАМНОГО больше чем проблем. Я это когда-то расписывал на ruSO.
все перечисленные проблемы в nginx решаются
Лучшее решение любой проблемы — в первую очередь не создавать её себе на ровном месте
плюшек от nginx НАМНОГО больше чем проблем
Прочитал все по диагонали, все перечисленное например решается через traefik, который значительно быстрее.
Ну то есть в итоге вы всё равно предлагаете ставить какой-то дополнительный сервер перед питоном? Тогда на этом можно закончить, потому что я предлагаю ровно то же самое.
Предлагаю иметь опции. Все это мне напоминает phpшников, которые 10 лет назад кричали, что apache лучше, чем nginx, потому что, видите ли, у них бенчмарки их php-кода показывают, что с apache быстрее.
Я не утверждаю, что должен стоять конкретно nginx (это просто самое популярное решение), но должно стоять хотя бы что-нибудь — хоть тот же traefik (не сильно-то он и slower). Без дополнительного реверс-прокси поднять что-то похожее на реальный продакшен-сервер получится примерно никогда — основной мой посыл вот в этом вот. (Наверное, допишу упоминание traefik в посте на ruSO)
traefik, который значительно быстрее.
И по вашей же ссылке английским по белому написано:
Traefik is obviously slower than Nginx
Асинхронный Python-код медленнее обычного кода