Быстрый Python порождается транслятором PyPy.
Пламенный привет посетителям этой страницы, пришедшим из социальных сетей, да и всем остальным тоже!
В апреле 2021-го года наблюдал удивительное явление: обильный поток посетителей из 4-х социальных сетей. В связи с этим настоятельно рекомендую всем неоднократно и регулярно посещать сайт rtbsm.ru — там в общих чертах изложена Российская Теннисная Балльная Система Марии (Шараповой).
Приглашаю всех полюбоваться на Фото и Видео красавицы Марии — надеюсь, что Вы поделитесь адресом сайта rtbsm.ru с друзьями и знакомыми.
Главная проблема — известить Марию, чтобы она лично как можно скорее заявила на весь мир о РТБСМ.
Быстрый Python получаем, используя современный усовершенствованный транслятор PyPy.
Наткнулся в Интернете на две полезные публикации о языке Python.
Привожу информацию со страницы https://dzen.ru/a/ZLsBmTGDsGOdqcCZ :
Сосед сравнил скорость Python и JS и онемел
ZDG
5,5 K подписчиков
5,8 K прочтений
22 июля 2023 г.В этом материале про Пирог обрабатывалась карта из плиток:
Пирог #13. Решение проблемы плиток
ZDG 7 июля 2023 г.В процессе обработки требовалось для каждой плитки получить значения её соседей сверху, снизу, справа и слева, а также опционально по диагонали.
Сама по себе такая деятельность называется конволюцией, или свёрткой (используется в различных фильтрах и нейросетях). Только в Пироге она применяется не в истинном математическом смысле, но тем не менее, никакой принципиальной разницы.
Давайте создадим на Питоне матрицу размером 1024 * 1024 элемента и заполним её случайными байтами (хотя это и не требуется, но на всякий случай):
А теперь пройдёмся по ней и для каждого элемента посчитаем такую свёртку: взять сумму элементов сверху, снизу, слева и справа, и разделить на 4. Т.е. получится некий фильтр размытия. Это полная условность, так как нас будет интересовать не результат, а просто скорость выполнения операций.
Обратите внимание на неудобство. Когда координаты (x, y) находятся на краю матрицы, то невозможно получить кого-то из соседей. Если при x = 0 попытаться взять x — 1, то выпадет ошибка. Приходится сначала проверять, есть ли сосед вообще, и только потом получать его значение.
Кроме того, если было доступно только 3 соседа, то и делить надо на 3, а если 2, то на 2. Значит, дополнительно надо ещё считать величину делителя (это переменная div).
Ветвления это плохо
На каждом шаге цикла исполняется 4 инструкции if. А всего – 4 184 304.
Условия порождают ветвления, а ветвления тормозят процессор, потому что он не может предсказать их выполнение и загрузить нужный код заранее.
Чтобы сократить количество условий, рассмотрим два альтернативных решения.
Сегментация циклов
Мы можем спокойно пройти по матрице без всяких условий, если не будем заходить на её края. А вот края надо будет пройти отдельно. Посчитаем верхнюю и нижнюю строку по своим правилам, а внутри всех строк будем ещё отдельно считать первый и последний элемент.
Получится вот так:
От этого кода рябит в глазах, но если не спеша его рассмотреть, то это просто куча отдельных операций и циклов. Зато посмотрите – ни одного условия. И ещё в каждом случае мы точно знаем, на сколько нужно делить, поэтому считать делитель не требуется.
Логические операции
Ещё один способ избавиться от условий это заменить их хитрыми логическими или математическими операциями.
Принцип тут такой. Допустим, к числу a надо прибавить число b. Но только если выполняется условие x > y.
if (x > y) { a += b; }
Но то же самое можно сделать, превратив условие x > y в множитель, равный 1 или 0:
a += b * (x > y);
Видите, здесь мы умножили b прямо на само выражение (x > y). Оно даёт результат true или false, которые автоматически конвертируются в 1 или 0. Следовательно, если условие выполняется, к a прибавится b * 1, а если нет, то b * 0.
А что, так можно было?
В общем случае – не всегда. В частных – сколько угодно
Читайте также:
А теперь тесты!
Запустим каждый тест по 4 раза с замерами времени, чтобы избежать случайных вариаций:
Результат (время выполнения в секундах):
Итак, мы видим, что сегментированный тест выполняется практически в 2 раза быстрее обычного. А вот тест с логическими операциями подвёл – оказался самым медленным. Видимо, операций получилось слишком много, чтобы дать выигрыш в скорости.
А что же JavaScript?
Я для сравнения написал такой же код на JS, его можно запускать онлайн:
https://js.do/nandakoryaaa/convo
Там картина такая же. Сегментированный тест самый быстрый, а логический самый медленный (хотя и не очень заметно). Но…
Эти числа – миллисекунды. То есть тест на Питоне выполняется около 0.5 секунды (500 миллисекунд), а такой же на JS – 10 миллисекунд. Это разница в 50 раз!
Я не знаю, почему. Пытался найти ошибки в коде JS, но не нашёл.
Погонять питона также можно онлайн:
https://onlinegdb.com/BvEQSovqV
В общем, оставляю Вас онемевать от этого факта :)
А мне придётся подумать вот над чем. В Пироге карта будет отрисовываться не в размере 1024 * 1024, но вполне вероятно что может быть и 512 * 512, то есть о производительности надо думать вот уже сейчас.
Но прорвёмся.
P.S. Новые результаты с Python JIT:
Это была преамбула.
Привожу информацию со страницы https://dzen.ru/a/ZLxVFPsRTGXsBH0s :
ChatGPT научил как ускорить Python, программисты пишут и нахваливают
ZDG
5,5 K подписчиков
541 прочтение
23 июля 2023 г.Надеюсь, эти идиотские заголовки радуют вас :)
В прошлый раз я сравнивал время выполнения различных методов на Питоне и на JS:
Меня неприятно (по отношению к Питону) удивил тот факт, что JS-код исполнялся в 50 раз быстрее такого же на Питоне. Но у него есть один секрет.
JIT
Это означает Just In Time Compiler.
Обычный компилятор просто вдумчиво компилирует программу. В отличие от него JIT занимается компиляцией прямо во время выполнения, то есть совмещает функции интерпретатора и компилятора.
Читайте также:
Деятельность JIT разбита на несколько стадий.
- Сначала по ходу выполнения программы делается анализ, определяются самые нагруженные и часто используемые места.
- Затем эти места компилируются – то есть компиляция применяется не ко всей программе, а только к её кускам.
- После компиляции получается код в формате LLVM – Low Level Virtual Machine, т.е. низкоуровневой виртуальной машины. Данный код может учитывать конкретную архитектуру, на которой он запускается, и поэтому по производительности приближается к настоящему машинному коду.
- Далее куски программы подменяются скомпилированным кодом LLVM, и вот получено значительное ускорение. JIT продолжает следить за поведением программы, и если она начала выполнять какие-то другие куски, то он скомпилирует и их.
Что там у Питона? Отвечает ChatGPT.
Сейчас технология JIT есть у многих языков, поэтому наверняка она должна быть и у Питона. Можно было обратиться в Гугл, но я спросил у ChatGPT. Я всё чаще пользуюсь им вместо Гугла, потому что он банально даёт нужный результат проще и быстрее.
Вот, например, выдача Гугла по запросу «python jit»:
Сразу и не сообразишь, куда тыкать, да?
А вот ответ от ChatGPT:
Из которого сразу стало понятно, что надо пробовать Numba и PyPy.
Numba
Тут не получилось абсолютно ничего. Для начала надо установить пакет numba:
pip install numba
А затем декорировать вычислительные функции специальным образом:
С виду всё просто, но у меня вылезли ошибки компиляции из-за того, что некоторые инструкции в программе оказались неподходящими для numba. А когда я их переделал, то результат оказался ещё медленнее, чем без numba. Удивительно, правда? Я не стал углубляться дальше.
PyPy
Это просто отдельная версия транслятора python, которая заменяет обычный Питон.
Я скачал архив отсюда:
А потом просто заменил всю папку, в которой установлен Питон, папкой из архива. И… всё, ничего не сломалось, программы продолжили работать как обычно. (Но рекомендую сохранить старую папку, если что-то пойдёт не так.)
Поправочка: модули, установленные в Питоне, не работают в PyPy – их надо устанавливать отдельно. При этом возможны проблемы с совместимостью.
Новые замеры времени показали ошеломительные результаты:
Напомню, что это время в секундах. Если раньше оно составляло 0.5, то теперь 0.005. Иначе говоря, достигнуто ускорение в 100 раз.
При этом разница между тестами стала совсем мизерная, и тогда я увеличил размер матрицы до 4096 * 4096:
Теперь разница более заметная (и более быстрые тесты по-прежнему лидируют), и всё равно общая скорость выросла многократно.
В общем, рекомендую :)
Итак, имеет смысл использовать быстрый транслятор PyPy который доступен для применения и в Linux, и в Windows.
!…
Приглашаю всех высказываться в Комментариях. Критику и обмен опытом одобряю и приветствую. В особо хороших комментариях сохраняю ссылку на сайт автора!
И не забывайте, пожалуйста, нажимать на кнопки социальных сетей, которые расположены под текстом каждой страницы сайта.
Продолжение тут…
Комментарии 205