Ускорение Python с помощью Rust: руководство по интеграции и бенчмарки 2026 | AiManual
AiManual Logo Ai / Manual.
21 Апр 2026 Гайд

Rust из Python: полное руководство по ускорению критического кода с примерами и бенчмарками

Как ускорить критический код Python в 100 раз с помощью Rust. Пошаговое руководство с PyO3, примерами и реальными бенчмарками на 21.04.2026.

Python тормозит? Время позвать тяжёлую артиллерию

Ты пишешь на Python. Данных много. Цикл for обрабатывает миллионы строк. И каждый раз, когда смотришь на прогресс-бар, думаешь: "Ну вот, опять можно сходить за кофе". Знакомо? Интерпретатор Python - не гоночный болид. Для CPU-bound задач он просто не создан.

Вариантов ускорения несколько: Cython, Numba, переписать на C++. Но есть один способ, который сочетает скорость нативного кода, безопасность памяти и современный инструментарий. Rust. Да, тот самый язык, который все хвалят за производительность и отсутствие segfault'ов.

Зачем тебе это? Если в проекте есть "узкое горлышко" - алгоритм, валидация данных, математические вычисления - его можно вынести в Rust и получить прирост в 10-100 раз. Как в Pydantic v2, где валидация работает на Rust под капотом.

Важно: Rust не заменит весь Python. Это дополнение для критических участков. Весь интерфейс, бизнес-логика высокого уровня остаются на Python.

Что происходит под капотом? Без магии

Python умеет вызывать функции из нативных библиотек через C ABI. Rust компилируется в ту же нативную библиотеку (.so на Linux, .dylib на macOS, .dll на Windows). Специальные крейты (пакеты Rust) типа PyO3 создают "мостик", который преобразует Python-объекты в Rust-типы и обратно.

Это не новая идея. Но PyO3 в 2026 году достиг невероятной зрелости. Версия 0.22 (актуальна на апрель 2026) поддерживает все последние фичи Python 3.12 и 3.13, асинхронные функции, GIL management и даже возможность писать классы на Rust, которые выглядят как родные Python-классы.

💡
Если боишься писать Rust с нуля, посмотри на AI-кодинг. Claude Code или аналогичные инструменты отлично генерируют Rust-код для таких интеграций.

Собираем инструменты: что нужно установить

Перед началом убедись, что система готова. Тебе понадобится:

  • Rust 1.85 или новее (на апрель 2026 стабильная версия 1.87). Устанавливается через rustup
  • Python 3.10+ (рекомендую 3.12 или 3.13)
  • Maturin 1.5+ - инструмент для сборки и публикации Rust-библиотек для Python
  • PyO3 0.22+ - основной крейт для связки Rust-Python

Установка займёт 5 минут:

# Установка Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Установка Maturin
pip install maturin
# или через pipx, что лучше для изоляции
pipx install maturin

1Создаём новый проект

Maturin умеет создавать проекты с готовой структурой. Выполни в терминале:

maturin init --bindings pyo3 my_fast_module
cd my_fast_module

Посмотри, что создалось: структура Rust-библиотеки с Cargo.toml и файлом lib.rs. Внутри уже есть пример функции sum_as_string.

Не называй проект просто "rust" или "fast". Имя станет именем Python-модуля. Лучше что-то вроде "data_processor_rs" или "fast_algorithms".

2Пишем первую полезную функцию

Открой src/lib.rs. Замени содержимое на реальный пример. Допустим, нам нужно быстро фильтровать список чисел, оставляя только чётные:

use pyo3::prelude::*;

/// Фильтрация чётных чисел из списка
/// Принимает список Python, возвращает новый список
#[pyfunction]
fn filter_even_numbers(py: Python, numbers: Vec) -> PyResult> {
    // В Rust это просто: filter и collect
    let result: Vec = numbers
        .into_iter()
        .filter(|&x| x % 2 == 0)
        .collect();
    
    Ok(result)
}

/// Модуль на Rust, который станет Python-модулем
#[pymodule]
fn my_fast_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(filter_even_numbers, m)?)?;
    Ok(())
}

Что здесь важно? Аннотация #[pyfunction] говорит PyO3, что эту функцию нужно экспортировать в Python. PyResult - специальный тип для возврата результатов или Python-исключений.

3Компилируем и устанавливаем

Теперь самое интересное - превращаем Rust-код в Python-модуль. В директории проекта выполни:

# Разработческий режим: устанавливает модуль в текущее виртуальное окружение
maturin develop
# Или для релизной сборки (оптимизированной)
maturin develop --release

Maturin сам найдёт активное виртуальное окружение Python, скомпилирует Rust-код и установит модуль. Если виртуального окружения нет, создай его заранее.

4Используем в Python

Открой Python-интерпретатор или создай test.py:

import my_fast_module

# Генерируем большой список
numbers = list(range(1_000_000))

# Вызываем Rust-функцию
result = my_fast_module.filter_even_numbers(numbers)

print(f"Найдено {len(result)} чётных чисел")
# Вывод: Найдено 500000 чётных чисел

Вот и всё. Функция работает. Но насколько быстрее? Давай измерим.

Бенчмарки: холодные цифры вместо громких слов

Создадим более сложный пример - вычисление суммы квадратов чисел. Сравним чистый Python, NumPy и Rust.

Добавим в lib.rs новую функцию:

#[pyfunction]
fn sum_of_squares(numbers: Vec) -> PyResult {
    let sum: f64 = numbers
        .into_iter()
        .map(|x| x * x)
        .sum();
    
    Ok(sum)
}

// Не забудь добавить её в модуль:
// m.add_function(wrap_pyfunction!(sum_of_squares, m)?)?;

Теперь Python-скрипт для сравнения:

import timeit
import numpy as np
import my_fast_module

# Готовим данные
data = list(range(1_000_000))
data_np = np.array(data, dtype=np.float64)

# Python версия
def sum_squares_python(nums):
    return sum(x * x for x in nums)

# NumPy версия
def sum_squares_numpy(arr):
    return np.sum(arr ** 2)

# Измеряем
python_time = timeit.timeit(
    lambda: sum_squares_python(data), 
    number=10
)

numpy_time = timeit.timeit(
    lambda: sum_squares_numpy(data_np), 
    number=10
)

rust_time = timeit.timeit(
    lambda: my_fast_module.sum_of_squares(data), 
    number=10
)

print(f"Python: {python_time:.3f} сек")
print(f"NumPy:  {numpy_time:.3f} сек")
print(f"Rust:   {rust_time:.3f} сек")
Метод Время (10 запусков) Ускорение относительно Python
Чистый Python ~2.8 сек 1x (база)
NumPy ~0.15 сек ~18x
Rust (PyO3) ~0.08 сек ~35x

Rust в два раза быстрее NumPy для этой задачи. Почему? NumPy тратит время на создание промежуточного массива (arr ** 2). Rust работает с потоком данных без лишних аллокаций.

💡
Для сложной обработки документов, например в RAG-пайплайнах, Rust показывает ещё более впечатляющие результаты. Библиотека Kreuzberg v4 обрабатывает PDF в 10 раз быстрее Python-аналогов.

Ошибки, которые сломают тебе день

Интеграция языков - не игрушки. Вот что может пойти не так:

  • Гонка за GIL: Rust-функция по умолчанию захватывает Global Interpreter Lock. Если функция выполняется долго, она блокирует весь Python-интерпретатор. Решение: использовать #[pyfunction(signature = (...))] с опцией gil = false или выносить вычисления в отдельные потоки.
  • Утечки памяти: Rust автоматически управляет памятью, но если ты передаёшь Python-объекты в Rust и хранишь их дольше вызова функции, нужны специальные типы Py и правильное отслеживание ссылок.
  • Паника в Rust: Если Rust-код вызовет panic!(), Python-процесс аварийно завершится. Всегда обрабатывай ошибки внутри Rust, возвращай PyResult.

Пример безопасной функции с обработкой ошибок:

#[pyfunction]
fn safe_divide(a: f64, b: f64) -> PyResult {
    if b == 0.0 {
        // Возвращаем Python-исключение, а не паникуем
        Err(PyZeroDivisionError::new_err("division by zero"))
    } else {
        Ok(a / b)
    }
}

Когда Rust действительно нужен, а когда нет

Не всё стоит переписывать. Вот эмпирическое правило:

  • Да: Обработка больших массивов, математические вычисления, парсинг сложных форматов, криптография, симуляции.
  • Нет: CRUD-операции, веб-роутинг, простые преобразования данных, скрипты автоматизации.

Если твой проект связан с AI-агентами, возможно, тебе интереснее посмотреть на оркестраторы на Rust, чем оптимизировать отдельные функции.

А что насчёт AOT-компиляции Python?

Есть альтернатива - компиляция Python в нативный код через Nuitka или Cython. Иногда этого достаточно. Подробнее в статье Python без тормозов. Но если нужен максимальный контроль над памятью и процессором, Rust вне конкуренции.

Что делать, если не хочешь учить Rust?

Честно? Учить всё равно придётся. Но можно начать с малого:

  1. Используй AI-инструменты типа Claude Code 2.0 для генерации Rust-кода по описанию.
  2. Бери готовые Rust-библиотеки с Python-биндингами (например, полярс для работы с данными).
  3. Начни с переписывания самых простых функций, которые уже есть в Python.

Или рассмотри вариант автоматического перевода уязвимого C-кода в Rust, как в великом рефакторинге.

Вопросы, которые ты хотел задать, но стеснялся

Сложно ли поддерживать такой гибридный проект?

Да, сложнее, чем чистый Python. Нужно следить за совместимостью версий PyO3 и Python, обновлять Rust-компилятор. Но Maturin автоматизирует большую часть работы. И главное - выноси в Rust только стабильные, редко меняющиеся компоненты.

Можно ли отлаживать Rust-код, вызванный из Python?

Можно, но это требует танцев с бубном. Проще всего - логировать из Rust в файл или использовать println!() для дебага. Для серьёзной отладки придёшься запускать Python-процесс под gdb/lldb и подключаться к Rust-символам.

Какие типы данных эффективнее всего передавать?

Примитивы (числа) и простые векторы/массивы. Сложные структуры вроде словарей требуют конвертации и замедляют всё. Дизайни API так, чтобы минимизировать преобразования типов на границе Rust-Python.

И последний совет: перед тем, как погружаться в Rust, измерь свой код. Найдите реальное "узкое место" через профайлер. Может оказаться, что проблема не в скорости вычислений, а в медленном I/O или неоптимальном алгоритме. Rust ускорит только CPU-bound операции, а ожидание базы данных ему не подвластно.

Подписаться на канал