Почему этот код медленнее в Cython, чем в Python?
Я начинаю изучать Cython из-за проблем с производительностью. Этот конкретный код представляет собой попытку реализовать некоторые новые алгоритмы в области моделирования транспорта (для планирования).
Я решил начать с очень простой функции, что я буду использовать LOT (сотни миллионов раз) и определенно выиграет от увеличения производительности.
Я реализовал эту функцию тремя различными способами и протестировал их для одного и того же параметра (для простоты) по 10 миллионов раз каждый:
- Код Cython в модуле cython. Продолжительность: 3.35s
- Код Python в модуле Cython. Продолжительность: 4.88s
-
Код Python на главном script. Продолжительность: 2.98 с
Как вы можете видеть, код cython был на 45% медленнее, чем код python в модуле cython и на 64% медленнее кода, написанного на основном script. Как это возможно? Где я делаю ошибку?
Код cython:
def BPR2(vol, cap, al, be):
con=al*pow(vol/cap,be)
return con
def func (float volume, float capacity,float alfa,float beta):
cdef float congest
congest=alfa*pow(volume/capacity,beta)
return congest
И script для тестирования:
agora=clock()
for i in range(10000000):
q=linkdelay.BPR2(10,5,0.15,4)
agora=clock()-agora
print agora
agora=clock()
for i in range(10000000):
q=linkdelay.func(10,5,0.15,4)
agora=clock()-agora
print agora
agora=clock()
for i in range(10000000):
q=0.15*pow(10/5,4)
agora=clock()-agora
print agora
Я знаю, что проблемы, такие как трансцендентные функции (власть), медленнее, но я не думаю, что это должно быть проблемой.
Так как есть накладные расходы для поиска функции в пространстве функций, поможет ли она производительности, если я передал массив для функции и получил массив? Можно ли вернуть массив с помощью функции, написанной в Cython?
Для справки, я использую:
- Windows 7 64 бит
- Python 2.7.3 64 бит
- Cython 0.16 64 бит
- Windows Visual Studio 2008
Ответы
Ответ 1
Тестирование проводилось с использованием:
for i in range(10000000):
func(2.7,2.3,2.4,i)
Вот результаты:
cdef float func(float v, float c, float a, float b):
return a * (v/c) ** b
#=> 0.85
cpdef float func(float v, float c, float a, float b):
return a * (v/c) ** b
#=> 0.84
def func(v,c,a,b):
return a * pow(v/c,b)
#=> 3.41
cdef float func(float v, float c, float a, float b):
return a * pow(v/c, b)
#=> 2.35
Для максимальной эффективности вам нужно определить функцию в C и сделать статический тип возврата.
Ответ 2
Эта функция может быть оптимизирована как таковая (как в питоне, так и в cython, удаление промежуточной переменной происходит быстрее):
def func(float volume, float capacity, float alfa,f loat beta):
return alfa * pow(volume / capacity, beta)
Ответ 3
Когда Cython работает медленнее, это, вероятно, связано с преобразованиями типов и, возможно, усугубляется отсутствием аннотаций типа. Кроме того, если вы используете C-структуры данных в Cython, это будет иметь тенденцию быть быстрее, чем использование структур данных Python в Cython.
Я провел сравнение производительности между CPython 2.x(с и без Cython, с и без psyco), CPython 3.x(с и без Cython), Pypy и Jython. Pypy был, безусловно, самым быстрым, по крайней мере, для микро-теста:
http://stromberg.dnsalias.org/~strombrg/backshift/documentation/performance/