Cython — это язык программирования, который дополняет python возможностью типизированного задания переменных и возможностью компиляции в Си код, который в последствии можно скомпилировать в бинарник.
Python потрясающий язык программирования. Но скорость его выполнения оставляет желать лучшего. И как раз в этом нам может помоч cython. На данный момент он практически без труда умеет компилировать python код в си.
Давайте рассмотрим все на примере.
Вот код python для нахождения чисел Фибаначи.
def fib(n): if n==0: return 0 elif n==1: return 1 else: return fib(n-1) + fib(n-2) result = [] for i in range (30): result.append(fib(i)) print result
Ничего сложного. Быстро и удобно. Но сколько времени занимает выполнение?
$ time python fib.py [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229] real 0m0.933s user 0m0.926s sys 0m0.008s
А теперь рассмотрим тот же код cython.
cdef fib(int n): if n==0: return 0 elif n==1: return 1 else: return fib(n-1) + fib(n-2) result = [] for i in range (30): result.append(fib(i)) print result
Тот же код, только cdef вместо def и параметр, который передается в функцию помечен как целочисленный.
Скомпилируем этот код в си.
cython -2 --embed fib.pyx -o fib.c
embed — говорит компилятору, генерировать так же код main функции.
Теперь компилируем полученный файл при помощи gcc.
gcc fib.c -o fib `python-config --includes --ldflags`
Запускаем.
$ time ./fib [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229] real 0m0.135s user 0m0.128s sys 0m0.007s
Как видите, резульат — всем результатам результат!
Кроме того, можно скомпилировать cython модуль в разделяемую библиотеку и импортировать её в интерпритатор python.
Создадим функцию.
def helloFunction (): return 'Hello World!'
Компилируем.
cython -2 mycode.pyx -o mycode.c gcc -g -O2 -shared -o mycode.so mycode.c `python-config --includes --ldflags` -fPIC
Запускаем интерпритатор и пробуем выполнить.
$ python Python 2.7.8 (default, Nov 10 2014, 08:19:18) [GCC 4.9.2 20141101 (Red Hat 4.9.2-1)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import mycode >>> mycode.helloFunction() 'Hello World!'
А теперь наоборот! Выполняем функцию из C кода.
Создаем файл pyapp.pyx.
def helloFunction(): return "Hello world!" cdef public void start_app(): print helloFunction()
Компилируем.
cython pyapp.pyx -o pyapp.c
Создаем файл main.c
#include <Python.h> #include "pyapp.h" int main (int argc, char **argv) { printf ("Initializing Python Runtime...\n"); Py_Initialize (); /* инициализация нашего приложения */ initpyapp(); /* запускаем функцию */ start_app(); printf ("Cleanup...\n"); Py_Finalize (); return 0; }
Компилируем.
gcc -o app main.c pyapp.c `python-config --includes --ldflags`
Запускаем.
$ ./app Initializing Python Runtime... Hello world! Cleanup...
Сработало. Вот это да.