Найти в Дзене
Цифровая Переплавка

🐍 Лестница оптимизации: как заставить Python работать в 1600 раз быстрее

Python любят за простоту, но часто ругают за медлительность. Каждый год появляется новый бенчмарк, где Python оказывается в десятки или даже сотни раз медленнее C или Rust. Обычно после этого начинается спор: одни говорят, что «бенчмарки ничего не значат», другие — что «надо просто писать на нормальных языках». Но реальность, как обычно, сложнее. Один разработчик решил не спорить, а проверить: что именно происходит, если последовательно применять все известные способы ускорения Python. От простого обновления версии до JIT-компиляции, NumPy и даже Rust-модулей. Получилась своеобразная «лестница оптимизации» — каждый следующий шаг даёт ускорение, но требует всё больше усилий. И результат оказался неожиданным: Python можно ускорить до 1633 раз. Но есть нюанс. Главная причина медлительности Python — не интерпретатор и даже не GIL, как принято думать. Настоящая причина — гипердинамичность языка. Python позволяет: ⚙️ менять методы классов прямо во время выполнения
⚙️ подменять встроенные фун
Оглавление

Python любят за простоту, но часто ругают за медлительность. Каждый год появляется новый бенчмарк, где Python оказывается в десятки или даже сотни раз медленнее C или Rust. Обычно после этого начинается спор: одни говорят, что «бенчмарки ничего не значат», другие — что «надо просто писать на нормальных языках».

Но реальность, как обычно, сложнее.

Один разработчик решил не спорить, а проверить: что именно происходит, если последовательно применять все известные способы ускорения Python. От простого обновления версии до JIT-компиляции, NumPy и даже Rust-модулей.

Получилась своеобразная «лестница оптимизации» — каждый следующий шаг даёт ускорение, но требует всё больше усилий.

И результат оказался неожиданным: Python можно ускорить до 1633 раз.

Но есть нюанс.

🧠 Почему Python медленный

Главная причина медлительности Python — не интерпретатор и даже не GIL, как принято думать.

Настоящая причина — гипердинамичность языка.

Python позволяет:

⚙️ менять методы классов прямо во время выполнения
⚙️ подменять встроенные функции
⚙️ менять наследование классов на лету
⚙️ переопределять операторы.

Это удобно для разработчиков, но кошмар для оптимизации.

Когда CPU видит в C выражение:

a + b

он просто выполняет одну инструкцию.

В Python всё гораздо сложнее.

Интерпретатор должен проверить:

🧩 какой тип у a
🧩 какой тип у b
🧩 не переопределён ли оператор +
🧩 не является ли объект подклассом с собственным __add__.

Каждая операция — это цепочка проверок.

🧱 Цена Python-объекта

Ещё одна причина — сами объекты Python.

В C число занимает:

📦 4 байта

А Python-число выглядит примерно так:

📦 ссылка на тип
📦 счётчик ссылок
📦 размер числа
📦 само значение.

В итоге:

📈 около 28 байт

То есть 4 байта данных и 24 байта служебной информации.

Когда таких объектов миллионы, разница становится огромной.

🪜 Лестница оптимизации Python

Исследователь протестировал разные способы ускорения Python на трёх задачах:

⚙️ физическая симуляция n-body
⚙️ математический тест spectral-norm
⚙️ реальный pipeline обработки JSON.

Каждый инструмент оказался новой ступенью лестницы.

🚀 Шаг 1 — просто обновить Python

Самый дешёвый способ ускорения.

CPython 3.11 получил большой апдейт проекта Faster CPython.

Он добавил:

⚙️ адаптивную специализацию байткода
⚙️ inline-кэширование
⚙️ ускоренную обработку исключений.

Результат:

📈 примерно 1.4× ускорение

И это буквально бесплатный апгрейд.

Если проект всё ещё работает на Python 3.9 или 3.10 — вы буквально теряете производительность.

⚡ Шаг 2 — альтернативные интерпретаторы

Следующая ступень — другой runtime.

Самые известные:

⚙️ PyPy
⚙️ GraalPy.

Они используют JIT-компиляцию, превращая горячие участки Python-кода в машинный код.

Результаты впечатляют:

📈 PyPy — до 13× быстрее
📈 GraalPy — до
66× быстрее.

Но есть проблемы.

⚠️ не все библиотеки работают
⚠️ C-расширения могут тормозить
⚠️ иногда долгий старт программы.

🧩 Шаг 3 — mypyc

Интересный инструмент — mypyc.

Он компилирует типизированный Python-код в C.

То есть обычные аннотации типов:

def advance(dt: float, n: int) -> None:

уже позволяют компилятору оптимизировать код.

Результаты:

📈 2× – 14× ускорение

Причём без изменения синтаксиса языка.

Фактически это превращает Python в статически типизированный язык на горячих участках.

🔬 Шаг 4 — NumPy

Если задача связана с математикой или матрицами, начинается магия.

NumPy выполняет вычисления не в Python, а в оптимизированных библиотеках:

⚙️ BLAS
⚙️ SIMD
⚙️ многопоточность.

Результат в тесте spectral-norm:

📈 520× ускорение

Да, именно так.

Python здесь работает просто как оркестратор для C-кода.

🧠 Шаг 5 — JAX и JIT-компиляция

Самый неожиданный результат показал JAX.

Это библиотека для научных вычислений, которая компилирует код через систему XLA JIT.

В тесте spectral-norm:

📈 1633× быстрее Python

То есть программа, которая работала 14 секунд, выполняется за 8.6 миллисекунды.

Причина проста.

JAX компилирует всю функцию целиком, не возвращаясь в Python между операциями.

⚙️ Шаг 6 — Numba

Numba — ещё один JIT-компилятор, но проще в использовании.

Достаточно добавить один декоратор:

@njit

И функция будет компилироваться через LLVM.

Результаты:

📈 56× – 135× ускорение

Но есть ограничения.

Numba любит:

⚙️ NumPy-массивы
⚙️ численные типы.

А вот строки и словари ему не нравятся.

🧱 Шаг 7 — Cython

Cython позволяет писать C-подобный код в синтаксисе Python.

Он компилируется в C-расширение.

Результаты:

📈 до 124× быстрее

Но тут начинается сложность.

Чтобы получить максимум скорости, нужно:

⚙️ понимать модель памяти C
⚙️ вручную указывать типы
⚙️ избегать скрытых медленных операций.

Без этого Cython может работать почти так же медленно, как Python.

🦀 Последняя ступень — Rust

На вершине лестницы находится Rust через PyO3.

Здесь горячие участки кода пишутся на Rust, а Python используется как оболочка.

Результат:

📈 113× – 154× ускорение

Но самое интересное — не в скорости.

Rust может вообще не создавать Python-объекты.

Например, он может:

⚙️ парсить JSON напрямую
⚙️ работать с нативными структурами
⚙️ передавать Python только готовый результат.

🧩 Реальность: потолок часто всего 4×

Самый честный результат исследования связан не с математикой, а с реальной задачей.

Pipeline обработки JSON-данных.

Когда данные уже представлены как Python-словарь:

📈 CPython → Cython = всего 4× ускорение

Почему?

Потому что главный тормоз Python — создание объектов.

Особенно:

⚠️ dict
⚠️ строки
⚠️ списки.

Именно поэтому настоящая оптимизация часто выглядит так:

👉 не ускорить цикл
👉
перестать создавать миллионы Python-объектов.

🧠 Мой главный вывод

Вся эта лестница отлично показывает одну важную мысль.

Python медленный не потому что язык плохой.

Он медленный потому, что:

🧠 создаёт много объектов
🧠 проверяет типы во время выполнения
🧠 остаётся максимально динамичным.

Но если вынести тяжёлые вычисления в:

⚙️ NumPy
⚙️ JAX
⚙️ Numba
⚙️ Cython
⚙️ Rust

— Python превращается в очень быстрый управляющий язык.

И это его настоящая роль.

🔮 Когда стоит оптимизировать

Есть простое правило, которое подтвердило это исследование.

🧠 сначала профилируй код
🧠 потом оптимизируй.

Часто оказывается, что:

⚙️ программа упирается в сеть
⚙️ или в базу данных
⚙️ или в чтение файлов.

В этих случаях оптимизация Python-циклов вообще ничего не даст.

Но если задача вычислительная — Python может стать быстрее в тысячу раз.

Главное — выбрать правильную ступень лестницы.

Источники

🔗 https://cemrehancavdar.com/2026/03/10/optimization-ladder/

🔗 https://telegra.ph/Lestnica-optimizacii-Kak-zastavit-Python-letat-i-stoit-li-ehto-usilij-03-14

🔗 https://github.com/cemrehancavdar/faster-python-bench