Python — довольно простой в освоении язык, по сравнению с некоторыми другими языками код на нём пишется очень быстро. Но в жертву приносится скорость выполнения кода. Перепишем часть Python-кода в Rust и импортируем этот код в виде пакета Python в проект. Получим сверхбыстрый пакет Python, который сможем импортировать и использовать, как любой другой пакет. В качестве бонуса добавим многопроцессорность и в итоге получим функцию, которая примерно в 150 раз быстрее обычного кода на Python. Проблему решим в 6 шагов: Пакет maturin скомпилирует Rust-код и преобразует его в готовый к работе пакет Python. Важно понять, почему функция работает медленно. Давайте представим, что проекту требуется функция подсчёта количества простых чисел в диапазоне между двумя другими числами: Пожалуйста, обратите внимание на то, что: Функция primecounter_py(10, 20) вернёт 4 (11, 13, 17 и 19 — простые числа) и количество выполненных функцией проверок на простое число. Небольшие диапазоны выполняются очень быстро, но на больших вы увидите снижение производительности: Чем больше диапазон, тем меньше скорость функции. Код может быть медленным по многим причинам: из-за ввода-вывода, ожидания API, оборудования или архитектуры Python как языка. У нас последний случай. Подход к обработке переменных в Python делает язык очень простым, но он страдает небольшим снижением скорости, которое очевидно, когда приходится выполнять много вычислений. С другой стороны, эта функция очень подходит для оптимизации с помощью Rust. Множество проблем со скоростью можно решить выполнением нескольких задач одновременно. Для разделения всех задач на несколько ядер можно использовать несколько процессоров, но мы придерживаемся оптимизации на Rust, ведь так мы сможем добиться распределения выполнения более быстрой функции. Задачи с большим количеством операций ввода-вывода, например ожидание API, можно оптимизировать при помощи потоков. Чтобы увеличить скорость выполнения таких задач, ознакомьтесь с этой статьей или статьёй ниже о том, как задействовать несколько процессоров. Ниже устанавливаем зависимости и создаём все файлы и папки для кода на Rust и его сборки в пакет. Создайте виртуальную среду и активируйте её. Затем установите maturin; он поможет преобразовать код Rust в пакет Python: Каталог my_rust_module будет содержать код на Rust: Вызовем метод .init. Вы увидите несколько вариантов на выбор, из них выберите pyo3. Пакет maturin создаст файлы и папки, структуру которых вы увидите ниже: Самый важный файл здесь — это /my_rust_module/src/lib.rs. Именно этот файл будет содержать код, который мы собираемся превратить в пакет Python. Обратите внимание, что maturin создал конфигурацию проекта — файл Cargo.toml. Кроме конфигурации, этот файл содержит все зависимости (например, requirements.txt). Я отредактировал его, чтобы он выглядел вот так: Теперь мы готовы воссоздать нашу функцию Python в Rust. Не будем слишком глубоко погружаться в синтаксис Rust, а сосредоточимся на том, как заставить код на Rust работать с Python. Сначала создадим функцию на чистом Rust, затем поместим её в пакет, который сможем импортировать и использовать в Python. Если вы никогда не видели код Rust, то приведённый ниже код может немного сбить с толку. Самое главное, что функция primecounter — это чистый Rust; она не имеет ничего общего с Python. Откройте /my_rust_module/src/lib.rs и вставьте в него этот код: Пройдёмся по самому важному в коде: Эта часть может показаться самой сложной, но maturin облегчает работу. Просто выполните эту команду: Команда компилирует весь код Rust, оборачивает его в пакет Python и записывает пакет в каталогyour_project_dir/my_rust_module/target/wheels. Далее мы установим наш Wheel-пакет. В приведённых ниже примерах я работаю в среде Debian (через Windows WSL), что немного упрощает компиляцию кода на Rust, ведь нужные компиляторы уже установлены. Сборка на Windows тоже возможна, но, скорее всего, вы получите сообщение типа Microsoft Visual C++ 14.0 or greater is required. Это означает, что у вас нет компилятора. Проблема решается установкой инструментов сборки C++. Установить созданный Wheel-пакет можно командой pip install: Теперь можно рабоать с модулем: Давайте вызовем обе версии функций с несколькими аргументами: Они возвращают результат и количество вычисленных ими чисел. В приведённом выше обзоре вы видите, что, когда дело доходит до вычислений в секунду, Rust превосходит Python в 27 раз. Код ниже распределяет числа, которые нам нужно вычислить, на все ядра процессора: Снова попробуем найти все простые числа в диапазоне от 0 до 100 000. Теперь это означает, что нужно выполнить почти 500 млн. проверок. Как видите, Rust выполняет эти проверки за 0,88 секунды. При многопроцессорной обработке процесс завершается за 0,16 секунды — это в 5,5 раз быстрее, то есть 2,8 млрд. вычислений в секунду. В сравнении с первоначальной функцией Python с единственным процессором мы увеличили количество вычислений с 18,8 млн. до 2,8 млрд. в секунду. Это означает, что наша функция теперь примерно в 150 раз быстрее.  Data Science и Machine Learning Python, веб-разработка Мобильная разработка Java и C# От основ — в глубину А также