Итак, что такое Cython?
Cython – это язык, который очень-очень похож на Python с добавлением синтаксических изюминок. Для того, чтобы убедиться в этом давайте взглянем на пример функции, реализованной на Python:
def is_prime_python(n):
for i in range(2, n):
if n % i == 0:
return False
return True
%%time
_ = is_prime_python(6_700_417)
Output:
CPU times: user 577 ms, sys: 4.35 ms, total: 582 ms
Wall time: 584 ms
Приведен простейший пример реализации проверки числа – простое число или нет. В качестве аргумента было взято большое число и видно, что Python проверяет это число примерно за полсекунды.
Теперь рассмотрим визави – Cython и реализацию его функции проверки числа:
%%cython
def is_prime_cython(int n):
cdef int i
for i in range(2, n):
if n % i == 0:
return False
return True
%%time
_ = is_prime_cython(6_700_417)
Output:
CPU times: user 23.1 ms, sys: 0 ns, total: 23.1 ms
Wall time: 26.8 ms
На первый взгляд отличий в коде практически нет, однако по результатам производительности видно превосходство Cython почти в 25 раз.
Давайте разберемся в чем же дело.
Разница состоит в том, что Cython в отличие от Python статически компилируемый и в нем есть, скажем, синтаксический сахар, который позволяет добавить статическую информацию о типах. В примере реализации функции на Python (напомню, что данный язык динамически типизируемый) в качестве аргумента подается какое-то n, а это n может оказаться чем угодно. И из-за, казалось бы, такой мелочи Python очень медленный. Интерпретатор Python совершает очень много действий для того, чтобы выяснить что же находится в этой переменной n.
В Cython, как и в таких языках как Java, C++, явно указывается то, что переменная n имеет тип int и переменная в цикле i также имеет тип int. Из-за этих явных указаний типов в переменной и происходит ускорение кода, так как больше нужно думать о том, какой это объект, какой у него тип данных и т.д.
На краткой схеме пайплайна Cython видно, что Cython код транслируется в C/C++ код, а далее компилируется в питоновское расширение .pyd, которое потом уже может использоваться с помощью Python. Это тоже одна из причин почему Cython супербыстрый.
Возникает хороший вопрос: «как компилировать Cython?». А на самом деле компилировать его очень даже просто. В примере реализации функции на Cython вызывается команда %%Cython, которая в свою очередь компилирует Cython код в ячейке.
Как мы знаем в С/С++ необходимо использовать Visual Studio, писать, запускать, компилировать, поэтому всё это бывает довольно сложно и вопрос, который возникает в случае с компилируемым языком «насколько сложно его компилировать?». В случае с Cython – супер просто. Условно в Jupyter ноутбуке написали код, вызвали команду %%Cython и код скомпилирован – его можно использовать. Если же имеется какой-то Cython код в файле, то необходимо просто импортировать install(), вызвать его. Соответственно, когда импортируются какие-то функции из файла, то Cython автоматически скомпилирует этот код.
Код, написанный в редакторе:
def is_prime_cython(int n):
cdef int i
for i in range(2, n):
if n % i == 0:
return False
return True
Теперь импортируем его следующей командой:
from pyximport import install
install()
from prime_check import is_prime_cython
Промежуточные итоги:
Cython - компилируемый язык;
Его синтаксис очень похож на Python, но с некоторыми дополнениями для статической типизации;
Статическая типизация + компиляция = скорость;
Писать только Python код, в случае Cython, совершенно нормально;
Нет никаких проблем с компиляцией.
Знатоки Numba скажут: зачем смотреть в сторону Cython, если можно просто использовать декоратор из Numba и код существенно прибавит в быстродействии.
Поговорим немного о разнице.
Напишем то же самый код для проверки числа только теперь сравним все полученные результаты:
Python |
Cython |
Numba |
|
|
|
|
|
|
CPU times: user 753 ms, sys: 3.75 ms, total: 756 ms Wall time: 783 ms |
CPU times: user 21.3 ms, sys: 139 µs, total: 21.5 ms Wall time: 21.5 ms |
CPU times: user 113 ms, sys: 1.18 ms, total: 114 ms Wall time: 115 ms |
Видно, что добавив декоратор @numba.njit, код ускорился почти в 5 раз и нет необходимости добавлять что-то лишнего, как в случае Cython. И зачем тогда изучать Cython, если везде можно обходиться одними декораторами от Numba?
У Cython есть одно большое преимущество перед Numba. Поскольку Cython язык, в нем есть всякие вещи по типу классов, в то время как Numba просто компилятор (не язык). Поэтому Cython может быть объектно-ориентированным, а Numba не может работать с классами нормально.
И другие плюсы Cython:
Cython поддерживает многомерные массивы (включая Numpy), следовательно более быстрый доступ к данным;
Cython выполняет множество проверок за вас: проверка границ массива, деление на ноль, переполнение;
Cython не ограничивается численными вычислениями.
Однако можно задаться вопросом: «зачем нам такой Python, если Cython это по сути тот же Python только быстрее и вообще он идеальный». Тем не менее и в Cython есть свои проблемы. Порой Cython код сложно отлаживать: когда допускается одна ошибка, синтаксический анализатор Cython проходит по всему коду, как лавина, и после одной ошибки возникает миллион других ошибок. Поэтому совет – смотрите самый верх (первые строчки) в сообщении об ошибке.
Документация не самая лучшая, так как это своего рода набор туториалов, то есть азы изучить можно, но если необходимо углубится в какой-то функционал, то трудно найти или практически невозможно найти описание.
Когда пишется оптимизированный код на Cython, он начинает походить на C, а C без соответствующей культуры начинает превращаться в какую-то кашу.
Просуммируем полученные знания:
Cython быстрый как C;
Поскольку это язык, то он очень гибкий;
Легко оборачивать C/C++ код;
Отладка Cython кода может быть проблемой;
Не лучшая документация.
Проекты, использующие Cython
Существующие проекты, которые используют Cython подтверждают тот тезис, что Cython создан не только для каких-то математических задач. Так Quora – веб-сайт, на котором отвечают на всякие вопросы, имеет очень загруженный трафик. Чтобы избавиться от проблем, которые преследуют в Python, этот сайт решили написать на Cython. К тому же уже знакомые библиотеки Pandas, а также Scikit-Learn используют язык Cython для улучшения своего функционала.
Финальные итоги:
Cython – это Python с некоторыми статическими вещами для скорости;
Cython отлично подходит для ускорения приложений Python;
Упакован множеством замечательных функций: оборачивание C/C++ кода, параллельные вычисления;
Не ограничивается численными вычислениями.
Комментарии (4)
WinPooh32
13.07.2022 10:58В качестве альтернативы можно посмотреть на транслятор обычного Питона (а не новый язык как в случае Cython) в Си: github.com/Nuitka/Nuitka
Без каких-то особых проблем на нем даже смог скомпилировать такой крупный проект как youtube-dl !
alextretyak
15.07.2022 15:00-1Есть такой код на Python (который считает k-ое по счёту простое число для k = 1 000 000).
Скрытый текстimport math def prime(): k = 1000000 n = k * 17 primes = [True] * n primes[0] = primes[1] = False for i in range(2, int(math.sqrt(n)) + 1): if not primes[i]: continue for j in range(i * i, n, i): primes[j] = False for i in range(n): if primes[i]: if k == 1: return i k -= 1 print(prime())
Я попытался переписать его под Cython.Скрытый текстimport math from libc.stdlib cimport malloc, free def prime(): cdef int k = 1000000 cdef int n = k * 17 cdef bint *primes = <bint *>malloc(17000000 * sizeof(bint)) cdef int i, j for i in range(17000000): primes[i] = True primes[0] = False primes[1] = False for i in range(2, int(math.sqrt(n)) + 1): if not primes[i]: continue for j in range(i * i, n, i): primes[j] = False for i in range(n): if primes[i]: if k == 1: free(primes) return i k -= 1
В результате получилось всего лишь в 5 раз быстрее.
Что не так в приведённом Cython-коде?
(Для сравнения: оригинальный Python-код [вообще без каких-либо изменений] ускоряется посредством траспайлера Python → 11l → C++ почти в 20 раз, что сопоставимо по скорости с реализацией на C/C++.)
DiligentMetal
А насколько Cython совместим с библиотеками и с модулями, или где приведен перечень, которые работают с Cython? Меня интересует работа с jaydebeapi, os и glob.
Hivemaster
Полная совместимость. Результат работы Cython - это pyd, бинарные модули Python. Грубо говоря виртуальной машине Python без разницы выполняет ли она скрипт, или бинарный модуль.