
Дошли руки до Cythona, спасибо самоизоляции. Проблема прозаична — как ускориться на python с минимальными потерями в синтаксисе. Один из подходов — использование Сython (смесь С и python).
Не давала покоя публикация с громким названием. Но из содержания публикации мало что можно вынести, так как формулы и результирующая таблица неверны. Попробуем дополнить картину, начатую авторами поста и расставим точки над и.
*Тесты проводились на odroid xu4, ubuntu mate, python 2.7.17.
Cython ставится просто (pip install cython).
Будем мучить все те же числа Фибоначчи. Создадим файлы для тестов прироста производительности. Для языка python (test.py):
def test(n): a, b = 0.0, 1.0 for i in range(n): a, b = a + b, a print (a)
Для языка cython(test2.pyx):
def test2(int n): cdef int i cdef double a=0.0, b=1.0 for i in range(n): a, b = a + b, a print (a)
Файл cython требует предварительной сборки. Для него создадим setup.py c содержимым:
from distutils.core import setup from Cython.Build import cythonize setup(ext_modules=cythonize('test2.pyx'))
И соберем:
python setup.py build_ext --inplace
Теперь возьмем файл из упомянутого поста с тестами и немного его поправим, добавив возможность вводить собственное число на старте (tests.py):
import test import test2 import time number = input('enter number: ') start = time.time() test.test(number) end = time.time() py_time = end - start print("Python time = {}".format(py_time)) start = time.time() test2.test(number) end = time.time() cy_time = end - start print("Cython time = {}".format(cy_time)) print("Speedup = {}".format(py_time / cy_time))
Посмотрим, что получилось:
python tests.py
Результаты:
Для python 2.7:
enter number: 10 Python time = 1.62124633789e-05 Cython time = 4.05311584473e-06 Speedup = 4.0 enter number: 100 Python time = 3.40938568115e-05 Cython time = 5.00679016113e-06 Speedup = 6.80952380952 enter number: 1000 Python time = 0.000224113464355 Cython time = 1.19209289551e-05 Speedup = 18.8 enter number: 100000 Python time = 0.0200171470642 Cython time = 0.000855922698975 Speedup = 23.3866295265
Для python 3:
enter number: 10 Python time = 7.653236389160156e-05 Cython time = 2.8133392333984375e-05 Speedup = 2.7203389830508473 enter number: 100 Python time = 8.678436279296875e-05 Cython time = 3.170967102050781e-05 Speedup = 2.736842105263158 enter number: 1000 Python time = 0.00031876564025878906 Cython time = 4.673004150390625e-05 Speedup = 6.821428571428571 enter number: 100000 Python time = 0.01643967628479004 Cython time = 0.0004260540008544922 Speedup = 38.5858981533296
*модуль test2.pyx «пересобирался» командой:
python3 setup.py build_ext --inplace
**устанавливался cython:
pip3 install cython
Можно обойтись без сборки test2.pyx с использованием setup.py, для этого необходимо просто в файл tests.py добавить строки:
import pyximport pyximport.install()
Теперь test2.pyx будет собираться на лету при каждом запуске tests.py, а файлов в папке будет меньше.
Как завести cython на windows.
Несмотря на то, что cython допускает сборку файлов как под python3, так и python2, получить готовый рецепт под python3
С python3 работает команда сборки:
python setup.py build_ext -i --compiler=msvc
Однако для ее полноценной работы необходима установка части компонентов visual studio 2019. Что именно устанавливать, указано в решении здесь.
Поэтому существует два рабочих варианта, которые позволяют поработать (собрать файл) в windows c cython.
Первый использует python2.7 и компилятор mingw.
Процедура следующая.
1.Устанавливаем сам cython под python2.7:
py -2 -m pip install cython
2.Устанавливаем компилятор mingw:
mingw
3.После установки компилятора и добавления его в PATH windows файл формата .pyx можно собирать командой:
python setup.py build_ext -i --compiler=mingw32
Второй использует python3.x и компилятор msvc.
Как запустить cython в jupyter notebook.
Иногда необходимо протестировать работу кода наглядно, используя jupyter. Чтобы каждый раз не компилировать код в cmd, можно использовать cython прямо в ячейках jupyter.
Для этого импортируем cython, выполнив в ячейке jupyter:
%load_ext cython
И выполним в следующей ячейке какой-нибудь код:
%%cython -a import numpy as np cdef int max(int a, int b): return a if a > b else b cdef int chebyshev(int x1, int y1, int x2, int y2): return max(abs(x1 - x2), abs(y1 - y2)) def c_benchmark(): a = np.random.rand(1000, 2) b = np.random.rand(1000, 2) for x1, y1 in a: for x2, y2 in b: chebyshev(x1, x2, y1, y2)
Если все выполнено успешно, то вывод будет таким:

