2012-06-25 4 views
11

Я начинаю изучать Cython из-за проблем с производительностью. Этот конкретный код представляет собой попытку реализовать некоторые новые алгоритмы в области моделирования транспорта (для планирования).Почему этот код медленнее в Cython, чем в Python?

Я решил начать с очень простой функции, что я буду использовать LOT (сотни миллионов раз) и определенно выиграет от увеличения производительности.

Я реализовал эту функцию три различных способов и протестировал их для того же параметр (для простоты), в 10 миллионов раз каждые:

  • Cython код в модуле Cython. Продолжительность спектакля: 3.35s
  • Код Python в модуле Cython. Продолжительность спектакля: 4.88s
  • Python код на главном скрипте. Продолжительность работы: 2.98s

    Как вы можете видеть, код cython был на 45% медленнее, чем код python в модуле cython и на 64% медленнее кода, написанного на главном скрипте. Как это возможно? Где я ошибаюсь?

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 

И сценарий для тестирования заключается в следующем:

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 64bits - Python 2.7.3 64 бит - Cython 0.16 64 Bits - Windows Visual Studio 2008

+1

Итак, если вы думаете о передаче массива в функцию, предположительно, вы можете прорисовать код, и в этом случае вы считали, что делать что вы пытаетесь сделать просто с помощью [NumPy] (http://numpy.scipy.org/)? Конечно, функция в вашем примере может быть тривиально реализована на массивах с использованием NumPy. –

+0

Ну, это чрезвычайно тривиальная функция, и cython должен преобразовать 'PyObject *' в float, а затем обратно, не так ли? Похоже, что для такой маленькой функции много накладных расходов. – Voo

+1

Чтобы уточнить, ваша проблема заключается в том, что вы тратите большую часть своего времени на вызов функции, которая не улучшается с помощью Cython. Я предлагаю вам перефразировать ваш вопрос без ущерба для решения (Cython). Таким образом, у тех, кто обычно будет отвечать, будет больше работать. Небольшой пример того, как вы действительно используете код, будет полезен. –

ответ

1

Эта функция может быть оптимизирована как таковой (в как питон и Cython, удаление промежуточной переменной быстрее):

def func(float volume, float capacity, float alfa,f loat beta): 
    return alfa * pow(volume/capacity, beta) 
+1

Это точно не приведет к желаемому порядку увеличения скорости ... –

+0

Но это поможет. Попробуйте это, а затем посмотрите, где он устанавливает скорость. – C0deH4cker

+5

Нет, не будет. В этом и заключается суть проблемы с преждевременной оптимизацией. Положите свои усилия на алгоритмические улучшения. –

3

Тестирование проводилось с помощью:

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 и сделать тип возвращаемого статичным.

+0

Из любопытства, сделайте последние 2 лучше, если вы 'из libc.math cimport pow'? – mgilson

+0

Теперь я получаю 3,35 и 1,35 соответственно. Так да. –

+0

Несомненно, любое сокращение времени при установке статического типа возврата во внешнюю C-библиотеку будет затмевать из-за накладных расходов. Все ваши увеличения скорости сводятся к минимуму вызовов в библиотеки python. Кроме того, мне любопытно, что делает cython, чтобы оператор '**' быстрее, чем 'lib'math''. Вы можете опубликовать вывод C-кода? –

0

Когда 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/

Смежные вопросы