Запрос «популярен ли Python» редко значит то, что в нём написано. Человек, который его вбивает в поиск, обычно решает другое: брать ли язык для нового сервиса, нанимать ли под него людей, переписывать ли то, что уже работает. Индексы популярности тут не помощники — мы их даже не будем цитировать: они измеряют шум поисковых запросов, а не вашу ситуацию. До вас популярность доходит ровно через три канала: можно ли найти людей, есть ли готовая библиотека под задачу, кто подхватит проект через годы. Всё остальное — арифметика: какая доля процессорного времени вашего запроса уходит на сам язык и сколько это стоит в деньгах.
За два года сместилась не позиция Python в рейтингах — его роль в архитектуре бэкенда. Об этом разговор. А в конце вы подставите свои числа и получите свой ответ, не приняв ни одного чужого.
Что сместилось за два года
Из устройства типичного веб-сервиса следует простая вещь: запрос можно нести на себе или дирижировать им. Старая форма — монолит на классическом ORM-фреймворке вроде Django: запрос живёт внутри Python, каждая строка из базы оборачивается в объект, бизнес-логика исполняется на каждый ряд. Новая форма — худой обработчик. Фильтрация, сортировка и агрегация уехали в базу: её движок делает это эффективнее любого прикладного кода. Тяжёлая математика — в векторизованные библиотеки, которые под капотом написаны не на Python. Вызовы моделей — в отдельный инференс-сервис. Python остаётся решать, что вызвать, и склеивать результаты.
Почему так вышло? Экономика, а не заговор. Процессорное время на запрос стоит денег, и его выгодно выносить туда, где оно дешевле: в базу, в компилируемое расширение, в специализированный рантайм. Время инженера стоит дороже, и его выгодно тратить на логику, а не на борьбу с языком. Отсюда и форма современного Python-бэкенда: контрольная плоскость — на Python, плоскость данных — где-то ещё.
Из этой арифметики следует следствие, закрывающее половину споров вокруг языка. Если интерпретатор занимает малую долю времени запроса, его скорость почти не влияет ни на задержку, ни на стоимость. Именно поэтому язык может быть одновременно «медленным» и безальтернативным в самой горячей области: рантаймы, которые считают модели, написаны не на Python — Python лишь отправляет туда тензоры и ждёт. Противоречия нет, он просто не сидит в плоскости данных.
Ещё два смещения, покороче. Типизация из «по желанию» стала «по умолчанию»: после определённого размера кодовой базы цена рефакторинга без аннотаций превышает цену их ведения — это экономика, а не мода. Инструментарий перестал быть налогом: современные упаковщики и линтеры, переписанные на компилируемых языках, отрабатывают быстрее, чем человек переключает окно терминала. Медленной осталась одна часть — сам работающий код.
Про интерпретатор. Появились официальные сборки без глобальной блокировки, ведётся работа над JIT-компиляцией. Для типичного веб-сервиса это пока ничего не переворачивает: он живёт в многопроцессной модели воркеров, где GIL и так не главный ограничитель. Снятие блокировки выигрывает тем, кто держит вычисления в потоках одного процесса, — ниша узкая, и заходить туда стоит осознанно, а не «потому что теперь можно».
Для команды из всего этого следует одно практическое: знать долю своего сервиса так же необходимо, как знать расход памяти. Ниже — как её посчитать. Но сначала о том, как обычно не надо.
Тупик: ускорять, не измерив
Когда сервис «тормозит», порядок проб почти всегда одинаков.
Сначала переводят эндпоинты на async — в надежде на скорость. Async убирает ожидание ввода-вывода, но не добавляет вычислений: если запрос упирается в базу, выигрыш будет; если в процессор — не будет, зато появится «окрашенность» функций, когда один внутренний вызов заставляет переписывать всю цепочку наверх. Потом обновляют интерпретатор. Само по себе полезно, но ускорение касается только той доли запроса, что исполняется интерпретатором: общий выигрыш равен доле, помноженной на ускорение. Доля мала — на графике вы ничего не увидите и решите, что «не помогло», хотя помогло, просто не там. Наконец, начинают микрооптимизации: кеши, слоты, списочные включения — до всякого профилирования. Это ремонт случайной стены: красим ту, что под рукой, а не несущую.
Рабочий первый шаг скучнее. Снять сэмплирующий профиль типичного запроса — например, py-spy, он не требует трогать код — и выписать две величины: полное время ответа и процессорное время интерпретатора. Дальше опираемся только на них.
Модель расчёта: подставьте свои значения
Шаг 1 — доля языка. На типичном эндпоинте замерьте:
- T — полное время ответа;
- C — процессорное время вашего Python-процесса: работа, а не ожидание.
Доля языка D = C / T. Это единственная цифра, которая определяет, имеют ли споры о скорости отношение к вашему сервису.
Шаг 2 — чтение доли. Если D мала, язык не влияет на ваш SLO, и ускорять нужно остаток: базу, сеть, кеш, конфигурацию воркеров. Все аргументы «быстрее — медленнее» к вам не относятся, какой бы язык ни обсуждали. Если D велика — читайте дальше.
Шаг 3 — деньги. Возьмите месячную стоимость одного ядра из своего облака; если машины выделенные, поделите их стоимость на ядра — подставьте свою схему. Переведите в цену процессоро-секунды: месячную цену разделите на число секунд в месяце. Нижняя граница месячных затрат на язык:
З = C × Q × P,
где Q — число запросов этого типа за месяц, P — цена процессоро-секунды. Нижняя, потому что реальность дороже: пиковая ёмкость, резерв под отказы, неидеальное уплотнение контейнеров.
Шаг 4 — альтернатива без чужих бенчмарков. Не верьте таблицам из интернета — снимите коэффициент сами. Возьмите самый горячий эндпоинт, перепишите его на компилируемом языке или в виде расширения на C, погоняйте на своей нагрузке и получите k — во сколько раз упало процессорное время. Месячная экономия от переписывания:
Э = Q × C × (1 − 1/k) × P.
Сравнивать её нужно не с нулём, а с ценой владения вторым стеком: другой набор инструментов, другая кривая онбординга, вторые дежурные. Приведите обе величины к одной единице — инженеро-часам в месяц: экономию инфраструктуры поделите на стоимость инженеро-часа. Если на этом фоне экономия — копейки, не трогайте. Если сопоставима с долей ставки — переписывайте горячий путь, но не весь сервис: остальной код ускорения не даст, а цену владения поднимет.
Шаг 5 — сама популярность. В расчёт она входит теми тремя каналами, и каждый проверяется по вашим данным:
- найм: сколько релевантных откликов даёт вакансия за неделю — сравните с соседней вакансией на другом стеке;
- готовые библиотеки: есть ли зрелый пакет под каждую интеграцию — платежи, очереди, хранилища; если нет, его написание и поддержка лягут на вас, и это скрытая цена выбора;
- преемственность: если проект переживёт интерес нынешней команды, легко ли будет найти тех, кто подхватит.
Если по всем трём «да», аргумент популярности исчезает — остаются D и деньги из шагов 1–4.
Шаг 6 — если бэкенд в основном вызывает модели. Тогда в T доминирует инференс, и его надо считать отдельно: сначала доля, потом деньги. Мы разбирали такой расчёт в материале «Сколько стоит инференс на реальной нагрузке» — логика та же, только дорогая часть не база, а модель.
Позиция редакции
Мы считаем Python разумным дефолтом для нового бэкенда общего профиля при трёх условиях: типизация с первого коммита; осознанный выбор, что живёт в интерпретаторе, а что — вне его; async только там, где много одновременных ожиданий ввода-вывода. Аргумент «он популярный» мы в позицию сознательно не включаем: популярность — прокси-метрика, она работает лишь через каналы найма и готовых библиотек, и их проверяют по своим данным, а не по индексам.
Теперь условие, при котором мы неправы, — формулируем явно, а не между строк. Дефолт ложен, если одновременно: доля D на типичном запросе велика и проектированием её не уменьшить — то есть сам продукт и есть вычисления на каждый запрос (парсинг, трансформация, криптография, сжатие), — и готовых библиотек под задачу нет. Тогда Python — не выбор, а долг: берите компилируемый язык с первого дня. Второе условие фальсификации — рынок найма: если вакансия молчит неделями, экосистема для вас мертва, что бы ни говорили рейтинги, и это решает всё.
Развилка после подстановки чисел простая. Вышло «оставлять» — оставляйте и не тратьте квартал на сомнения: доля D не вырастет от того, что вы нервничаете. Вышло «переписывать» — начните с одного эндпоинта и снимите на нём k, прежде чем объявлять миграцию. Главный вопрос всё равно не «популярен ли Python», а «какую долю вашего запроса он съедает» — и теперь у вас есть способ это узнать.