Юрий Белк – Full stack Developer (страница 16)
Но это работает, только если:
– вы включили проверки и не отключаете их «ради скорости»;
– вы используете типы последовательно;
– вы аккуратно работаете с границами (входные данные из внешнего мира).
Практический вывод: типизация в Python – это инструмент качества, который нужно сознательно включать и поддерживать, иначе он «растворяется» в проекте.
Минус 2. Производительность часто ниже; async требует дисциплины
Python обычно медленнее по CPU‑задачам, чем Go/Java/Node (V8 часто быстрее в чистых вычислениях). В прикладном API это не всегда критично, потому что большинство запросов – это I/O:
– база данных;
– кэш;
– внешний сервис.
Но проблемы начинаются, когда:
– в запросе много преобразований данных;
– вы сериализуете/десериализуете большие объёмы JSON;
– вы делаете тяжёлые вычисления в обработчике запроса;
– вы случайно блокируете event loop (в async‑варианте).
Почему «async требует дисциплины»
FastAPI и современный Python‑стек часто используют `async`/`await`. Это мощно, но легко ошибиться:
– вы используете синхронную библиотеку внутри `async`‑эндпоинта;
– вы делаете блокирующий вызов (например, обычный HTTP‑клиент без async);
– вы запускаете CPU‑тяжёлое в том же потоке;
– вы не контролируете время ожидания и ретраи.
Снаружи это проявляется как странные симптомы:
– сервис «живой», но отвечает медленно;
– под нагрузкой резко растут задержки;
– метрики показывают, что CPU не загружен на 100%, но запросы висят.
Проблема не в том, что async «плохой». Проблема в том, что в Python легко смешать async и sync так, что вы сами себе создаёте пробки.
Обычно помогают практики:
– чётко выбирать: этот сервис в основном async или в основном sync;
– использовать подходящие библиотеки (async‑драйверы БД, async‑HTTP клиент);
– выносить CPU‑тяжёлое в фоновые воркеры;
– ограничивать параллелизм и ставить таймауты.
Минус 3. Параллелизм сложнее (GIL), обычно уходят в процессы/очереди
В Python есть известная особенность: GIL (Global Interpreter Lock) в CPython. Упрощённо: в одном процессе Python‑код не исполняется параллельно на нескольких ядрах так, как вы могли бы ожидать от потоков.
Что это значит для бэкенда:
– Для I/O‑нагрузки это часто не критично: пока вы ждёте сеть/БД, можно обрабатывать другие запросы.
– Для CPU‑нагрузки это становится проблемой: если у вас тяжёлая обработка данных, один процесс будет упираться в одно ядро.
Типичные решения в продакшене:
1) Масштабирование процессами
Запускают несколько воркеров веб‑сервера (несколько процессов). Это даёт использование нескольких ядер.
2) Очереди и фоновые задачи
CPU‑тяжёлое выносят из HTTP‑обработчика в отдельные воркеры: так API остаётся быстрым, а тяжёлая работа выполняется асинхронно.
3) Отдельные сервисы для тяжёлых расчётов
Иногда проще вынести вычисления в отдельный компонент (на другом языке или в отдельной инфраструктуре), чем бороться с ограничениями внутри одного API.
4) Нативные расширения
Для некоторых задач используют библиотеки, которые внутри реализованы на C/C++/Rust и обходят ограничения, потому что тяжёлая часть выполняется вне интерпретатора.
Практическая мысль: Python отлично работает как «клей» и как слой бизнес‑логики, но если ваш сервис – это постоянные тяжёлые вычисления на запрос, вам почти наверняка понадобится отдельная стратегия параллелизма.
Минус 4. Управление зависимостями и окружением может быть источником боли
Это не уникально для Python, но в Python это встречается чаще из‑за большого количества способов «как правильно» управлять пакетами.
В реальных проектах проблемы выглядят так:
– «у меня локально работает, в CI нет»;
– «после обновления зависимости всё сломалось»;
– «на сервере другая версия Python»;
– «библиотека тянет несовместимые версии зависимостей».
Эта боль сильно уменьшается, если:
– фиксировать версии зависимостей;
– использовать виртуальные окружения;
– контейнеризировать приложение;
– иметь понятный способ сборки (один, а не три разных в разных командах).
2.4. Когда выбирать Python
Сценарий 1. Продукты с аналитикой/ML и плотной работой с данными
Если в продукте важны:
– рекомендации;
– скоринг;
– сегментации пользователей;
– обработка событий и метрик;