Python — достаточно быстрый язык, однако он не такой быстрый, как языки, которые порождают скомпилированные программы. Это потому, что при использовании CPython, стандартной реализации языка, программа интерпретируется. Более точно, ваш код Python компилируется в байтовый код, который затем интерпретируется. Это хорошо подходит для изучения языка и случаев, когда производительность не так важна, поскольку вы можете сразу запускать программу без этапа компиляции.
Однако, по мере того, как язык набирает популярность, разработчики хотят создавать и быстро работающие программы на Python, поэтому за последние годы появилось несколько компиляторов Python, включая IronPython и Jython.
От переводчика: Python широко используется как для создания традиционных приложений, например, веб-сервисов, так и для приложений машинного обучения и обработки больших данных, которые используют язык только для управления потоком обработки, при этом сама обработка происходит в рамках расширений, которые реализованы на C. Однако, даже в случае последнего сценария использования, часть кода, которая выполняется в рамках Python может существенно замедлить все приложение, в связи с чем появились дополнительные способы расширения языка, например, Numba.
Высокая производительность — не единственная причина для компиляции; возможно, самый большой недостаток языков, таких как Python, заключается в том, что вы не имеете возможность не предоставлять свой исходный код, что является существенной преградой для реализации в языке алгоритмов и решений, являющихся коммерческой тайной.
Как ускорить Python
Я хотел сравнить несколько компиляторов Python на одной платформе, особенно те, которые поддерживают Python 3.x. В итоге я выбрал четыре, все они работают на Ubuntu Linux: Nuitka, PyPy, Cython и cx_Freeze.
Сравнение трансляторов Python
В качестве бенчмарка будет использоваться пакет PyStone, адаптация C-программы, которую сделал Гвидо ван Россум, создатель Python (сама C-программа была переводом Ада-программы). Я нашел версию бенчмарка от Кристофера Арндта, которая способна тестировать Python 3. Чтобы получить представление о базовой производительности, оценим производительность CPython (то есть стандартного Python) с PyStone.
$ python2 pystone.py 1000000 Pystone(1.1.1) time for 1000000 passes = 3.61152 This machine benchmarks at 276892 pystones/second $ python3 pystone.py 1000000 Pystone(1.1.1) time for 1000000 passes = 4.07254 This machine benchmarks at 245547 pystones/second
Как видите, между производительностью теста в Python 2 и 3 есть существенная разница (чем больше Pystones в секунду, тем лучше). В следующих разбивках все компиляторы используют Python 3.
Nuitka
В Ubuntu 18.04 установить Nuitka возможно с помощью APT:
$ sudo apt update $ sudo apt install nuitka clang
Результат выполнения бенчмарка для компилятора Nuitka:
⚡ УСКОРЯЕМ PYTHON в 20 РАЗ! | Новый способ :3
# Сборка для GCC $ nuitka pystone.py $ ./pystone.exe 1000000 Pystone(1.1.1) time for 1000000 passes = 2.67537 This machine benchmarks at 373780 pystones/second # Сборка для Clang $ nuitka pystone.py —clang $ ./pystone.exe 1000000 Pystone(1.1.1) time for 1000000 passes = 2.64646 This machine benchmarks at 377863 pystones/second # Использование GCC с оптимизацией $ nuitka pystone.py —lto $ ./pystone.exe 1000000 Pystone(1.1.1) time for 1000000 passes = 2.6195 This machine benchmarks at 381753 pystones/second
Как можно видеть, Nuitka позволила получить увеличение производительности на 50%, по сравнению со стандартной реализацией Python 3.
PyPy
Гидо ван Россум однажды сказал: «Если вы хотите, чтобы ваш код работал быстрее, вам, вероятно, следует просто использовать PyPy». Я загрузил переносимые двоичные файлы в папку, а в папке bin скопировал pystone.py. Затем я запустил это так: Мы просто установили PyPy 3 с помощью Ubuntu Snap:
$ sudo snap install pypy3 —classic
$ pypy3 pystone.py 1000000 Pystone(1.1.1) time for 1000000 passes = 0.359845 This machine benchmarks at 2.77897e+06 pystones/second $ pypy3 pystone.py 1000000 Pystone(1.1.1) time for 1000000 passes = 0.26776 This machine benchmarks at 3.73469e+06 pystones/second $ pypy3 pystone.py 1000000 Pystone(1.1.1) time for 1000000 passes = 0.147859 This machine benchmarks at 6.7632e+06 pystones/second
Для данного теста результаты выполнения до «разгона» показывают более 10 кратное, а после «разгона» более чем 26 кратное ускорение производительности.
Создание исполняемого файла требует больше работы. Вы должны написать свой Python в подмножестве RPython.
Cython
Cython — это не просто компилятор для Python; это языковое надмножество языка Python, который поддерживает взаимодействие с C/C ++. CPython написан на C, поэтому это язык, который обычно хорошо сочетается с Python:
$ sudo apt install cython3 pkg-config
Сборка программы с помощью Cython немного сложна. Это не похоже на Nuitka, которая просто работает из коробки:
$ cython3 pystone.py —embed $ gcc $(python3-config —includes) pystone.c -lpython3.6m -o pystone.exe $ ./pystone.exe 1000000 Pystone(1.1.1) time for 1000000 passes = 4.8549 This machine benchmarks at 205978 pystones/second
Производительность оказалась весьма низкой, гораздо ниже, чем у стандартного CPython. Однако, Cython требует, чтобы вы проделали дополнительную работу, указав типы переменных. Python — это динамический язык, поэтому типы не указываются; Cython использует статическую компиляцию, а использование переменных с типом Си позволяет создавать гораздо более оптимизированный код — документация довольно обширна и требует глубокого изучения.
Cx_Freeze
Cx_freeze — это набор скриптов и модулей для «замораживания» скриптов Python в исполняемые файлы. Установить cx_Freeze можно с помощью PIP3:
sudo pip3 install cx_Freeze —upgrade
$ cxfreeze pystone.py -O -s —target-dir dist Missing modules: ? __main__ imported from bdb, pdb ? _dummy_threading imported from dummy_threading ? _frozen_importlib imported from importlib, importlib.abc ? _frozen_importlib_external imported from importlib, importlib._bootstrap, importlib.abc ? _winapi imported from subprocess ? _winreg imported from platform ? java.lang imported from platform ? msvcrt imported from subprocess ? nt imported from ntpath, os, shutil ? org.python.core imported from copy, pickle ? os.path imported from os, pkgutil, py_compile, tracemalloc, unittest, unittest.util ? vms_lib imported from platform ? winreg imported from mimetypes, platform This is not necessarily a problem — the modules may not be needed on this platform.
Copying data from package collections. Copying data from package email. Copying data from package encodings. Copying data from package html. Copying data from package http. Copying data from package importlib. Copying data from package logging. Copying data from package pydoc_data. Copying data from package unittest. Copying data from package urllib.
Copying data from package xml. $ dist/pystone 1000000 Pystone(1.1.1) time for 1000000 passes = 5.35072 This machine benchmarks at 186891 pystones/second
Как можно видеть, производительность даже ниже, чем у стандартного интерпретатора CPython. Данное решение разумно использовать только для упаковки всего Python-окружения в независимый исполняемый пакет. Стоит отметить, что для этой цели можно использовать и Pyinstaller.
Заключение
Я в восторге от производительности PyPy. Компиляция была очень быстрой, и приложение работало в десятки раз быстрее аналогов и оригинального кода CPython. Если вы хотите распространять бинарный файл, выбирайте Nuitka — решение дает как ускорение, так и позволяет выполнить упаковку кода.
От переводчика: в статье рассмотрено использование решений PyPy, Nuitka, Cython и Cx_Freeze для очень простого кода, который без проблем собирается данными трансляторами. Код, используемый в реальных приложениях, может быть затруднительно скомпилировать или его производительность может стать еще хуже, чем у стандартного Python. Необходимо производить бенчмарки на том коде, который вы собираетесь распространять, поскольку синтетические бенчмарки, как в этой статье не дают представления о реальном варианте использования, который будет в вашем случае.
Источник: netpoint-dc.com
Как ускорить программу в питоне
Кстате, ошибка в примере:
$ python -m timeit -s ‘d=dict.fromkeys(range(100))’ ‘try: x=d’ ‘except KeyError: x=42’
1000000 loops, best of 3: 0.548 usec per loop
Наверно должно быть:
Закладки на сайте Проследить за страницей |
Created 1996-2023 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |
Источник: www.opennet.ru
Cython: более чем 30-кратное ускорение Python-кода
Python — это язык, который любят многие программисты. Этим языком невероятно легко пользоваться. Всё дело в том, что код, написанный на Python, отличается интуитивной понятностью и хорошей читабельностью. Однако в разговорах о Python часто можно слышать одну и ту же жалобу на этот язык. Особенно тогда, когда о Python говорят знатоки языка C. Вот как она звучит: «Python — это медленно».
И те, кто так говорят, не грешат против истины.
В сравнении со многими другими языками программирования Python — это, и правда, медленно. Вот результаты испытаний, в ходе которых сопоставляется производительность разных языков программирования при решении различных задач.
Есть несколько способов ускорения Python-программ. Например, можно применять библиотеки, рассчитанные на использование нескольких ядер процессора. Тем, кто работает с Numpy, Pandas или Scikit-Learn, можно посоветовать взглянуть на программный комплекс Rapids, позволяющий задействовать GPU при проведении научных расчётов.
Все эти методики ускорения работы хороши в тех случаях, когда решаемые с помощью Python задачи могут быть распараллелены. Например — это задачи по предварительной обработке данных или операции с матрицами.
Но как быть в том случае, если ваш код — это чистый Python? Что если у вас есть большой цикл for , который вам совершенно необходимо использовать, и выполнение которого просто нельзя распараллелить из-за того, что обрабатываемые в нём данные должны обрабатываться последовательно? Можно ли как-то ускорить сам Python?
Ответ на этот вопрос даёт Cython — проект, используя который можно значительно ускорить код, написанный на Python.
Что такое Cython?
Cython, по своей сути, это промежуточный слой между Python и C/C++. Cython позволяет писать обычный Python-код с некоторыми незначительными модификациями, который затем напрямую транслируется в C-код.
Единственное изменение Python-кода при этом заключается в добавлении к каждой переменной информации об её типе. При написании обычного кода на Python переменную можно объявить так:
x = 0.5
При использовании Cython при объявлении переменной нужно указать её тип:
cdef float x = 0.5
Эта конструкция сообщает Cython о том, что переменная представляет собой число с плавающей точкой. По такому же принципу объявляют переменные и в C. При использовании обычного Python типы переменных определяются динамически. Явное объявление типов, применяемое в Cython — это то, что делает возможным преобразование Python-кода в C-код. Дело в том, что в C необходимо явное объявление типов переменных.
Установка Cython предельно проста:
pip install cython
Типы в Cython
При использовании Cython можно выделить два набора типов. Один — для переменных, второй — для функций.
Если речь идёт о переменных, то тут нам доступны следующие типы:
- cdef int a, b, c
- cdef char *s
- cdef float x = 0.5 (число одинарной точности)
- cdef double x = 63.4 (число двойной точности)
- cdef list names
- cdef dict goals_for_each_play
- cdef object card_deck
При работе с функциями нам доступны следующие типы:
- def — обычная Python-функция, вызывается только из Python.
- cdef — Cython-функция, которую нельзя вызвать из обычного Python-кода. Такие функции можно вызывать только в пределах Cython-кода.
- cpdef — Функция, доступ к которой можно получить и из C, и из Python.
Ускорение кода с использованием Cython
Начнём с создания Python-бенчмарка. Это будет цикл for , в котором выполняется вычисление факториала числа. Соответствующий код на чистом Python будет выглядеть так:
def test(x): y = 1 for i in range(1, x+1): y *= i return y
Cython-эквивалент этой функции очень похож на её исходный вариант. Соответствующий код нужно поместить в файл с расширением .pyx . Единственное изменение, которое нужно внести в код, заключается в добавлении в него сведений о типах переменных и функции:
cpdef int test(int x): cdef int y = 1 cdef int i for i in range(1, x+1): y *= i return y
Обратите внимание на то, что перед функцией стоит ключевое слово cpdef . Это позволяет вызывать данную функцию из Python. Кроме того, тип назначен и переменной i , играющей роль счётчика цикла. Не будем забывать о том, что типизировать нужно все переменные, объявленные в функции. Это позволит компилятору C узнать о том, какие именно типы ему использовать.
Теперь создадим файл setup.py , который поможет нам преобразовать Cython-код в C-код:
from distutils.core import setup from Cython.Build import cythonize setup(ext_modules = cythonize(‘run_cython.pyx’))
python setup.py build_ext —inplace
Теперь С-код готов к использованию.
Если взглянуть в папку, в которой находится Cython-код, там можно будет найти все файлы, необходимые для запуска C-кода, включая файл run_cython.c . Если вам интересно — откройте этот файл и посмотрите на то, какой С-код сгенерировал Cython.
Теперь всё готово к тестированию нашего сверхбыстрого C-кода. Ниже приведён код, используемый для тестирования и сравнения двух вариантов программы.
import run_python import run_cython import time number = 10 start = time.time() run_python.test(number) end = time.time() py_time = end — start print(«Python time = <>».format(py_time)) start = time.time() run_cython.test(number) end = time.time() cy_time = end — start print(«Cython time = <>».format(cy_time)) print(«Speedup = <>».format(py_time / cy_time))
Код этот устроен очень просто. Мы импортируем необходимые файлы — так же, как импортируются обычные Python-файлы, после чего вызываем соответствующие функции, делая это так же, как если бы мы всё время работали бы с обычными Python-функциями.
Взгляните на следующую таблицу. Можно заметить, что Cython-версия программы оказывается быстрей её Python-версии во всех случаях. Чем масштабнее задача — тем больше и ускорение, которое даёт использование Cython.
Число | Показатель Python Time | Показатель Cython Time | Показатель Speedup |
10 | 1.6689300537109375e-06 | 4.76837158203125e-07 | 3.5 |
100 | 3.337860107421875e-06 | 4.76837158203125e-07 | 7.0 |
1000 | 2.193450927734375e-05 | 9.5367431640625e-07 | 23.0 |
10000 | 0.0002090930938720703 | 6.4373016357421875e-06 | 32.481 |
100000 | 0.0021562576293945312 | 6.008148193359375e-05 | 35.89 |
1000000 | 0.02128767967224121 | 0.0005953311920166016 | 35.75 |
10000000 | 0.2148280143737793 | 0.00594782829284668 | 36.1187317112278 |
Итоги
Использование Cython позволяет значительно ускорить практически любой код, написанный на Python, не прилагая к этому особенных усилий. Чем больше в программе циклов и чем больше данных она обрабатывает — тем лучших результатов можно ждать от применения Cython.
Уважаемые читатели! Используете ли вы Cython в своих проектах?
Источник: temofeev.ru