Почему этот код медленнее в 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/