С чего начинать оптимизацию
Python обладает всеми достоинствами, кроме скорости. Интерпретация, динамическая типизация, объектная модель — всё, что делает язык удобным, обходится дорого. Наивный цикл на Python выполняется в десятки и сотни раз медленнее того же кода на C. Для скрипта, запускаемого раз в день, это несущественно, а для обработки терабайта данных с детектора или моделирования миллиона частиц разница составляет часы против недель.
Медленный код на Python почти всегда можно ускорить, не переписывая его целиком на C++. В настоящем разделе последовательно рассматриваются следующие темы:
- глава «Причины низкой скорости Python» объясняет, откуда берётся разница с C, и вводит инструменты измерения времени:
cProfile,line_profiler,py-spy,timeit; - глава «Оптимизация средствами самого Python» собирает приёмы, не требующие ничего, кроме самого языка: выбор структуры данных, встроенные функции, измерение и экономия памяти;
- глава «Скорость выполнения программ» последовательно ускоряет один и тот же расчёт: сначала приёмами самого языка, затем с помощью Numba и Cython и в завершение NumPy, а на расчёте пространственного заряда пучка показывает выигрыш от JIT-компиляции и параллелизма;
- глава «Многопоточность и GIL» объясняет, почему потоки в обычной сборке CPython не ускоряют вычисления, что представляет собой глобальная блокировка интерпретатора и в каких случаях помогают процессы и сборка Python без GIL;
- глава «Асинхронность» рассматривает цикл событий и
asyncio, опираясь на корутины из главы «Итераторы, генераторы и корутины», и показывает, как ожидать тысячи одновременно запущенных операций ввода-вывода; - глава «CUDA и вычисления на GPU» показывает, когда и как перенести расчёт на видеокарту с помощью CuPy и Numba;
- глава «Кластеры и воспроизводимое окружение для расчётов» переносит расчёт на вычислительный кластер: планировщик Slurm, массивы задач для независимых расчётов, MPI из Python для связанных, образы Apptainer для воспроизводимого окружения и настройка машин кодом с помощью Ansible.
Оптимизацию не проводят вслепую. Интуиция почти всегда ошибается относительно того, где программа проводит время; достоверно это показывает только профилировщик.
Слайды к главе. Основной материал раздела изложен также в лекции «Оптимизация и параллельные вычисления» (причины медленности, измерение и профилирование, приёмы языка, память, Numba и Cython, NumPy и BLAS, потоки, процессы, сборка Python без GIL и видеокарта) с демонстрациями в терминале; слайды лекции доступны на сайте книги и в PDF.