2013-02-08 7 views
3

У меня есть этот Cython код только для тестирования:Медленная скорость при возвращении заявление

cimport cython 

cpdef loop(int k): 
    return real_loop(k) 

@cython.cdivision 
cdef real_loop(int k): 
    cdef int i 
    cdef float a 
    for i in xrange(k): 
     a = i 
     a = a**2/(a + 1) 
    return a 

И я испытываю скорость diffence между этим Cython кода и того же кода в чистом питоне со скриптом вроде этого:

import mymodule 

print(mymodule.loop(100000)) 

Я получаю 80 раз быстрее. Но если я удалю два оператора return в коде cython, я получаю 800-900 раз быстрее. Зачем ?

Другое дело, если я запустил этот код (с возвратом) на своем старом ноутбуке ACER Aspire ONE, я получаю 700 раз быстрее и на новом рабочем столе i7 для ПК дома, в 80 раз быстрее.

Кто-нибудь знает почему?

+4

Трудно сказать - интересно, будет ли компилятор достаточно умен, чтобы увидеть, что 'real_loop' не обновляет какие-либо глобальные переменные, и он не меняет никаких аргументов, поэтому его можно превратить в no -op. – mgilson

+1

Вы пытались «разбить» два сгенерированных файла C, чтобы увидеть различия? Во всяком случае, возможно, это потому, что cython видит, что функции без 'return' бесполезны и вообще не работают. – Bakuriu

+1

@ Бакуриу да, это то, что я думаю. вероятно, вообще не делают петлю. Я не знаю, как вчера, когда я пытаюсь по-разному закодировать его, я получаю иногда смешную работу, например, в 12 000 раз быстрее. –

ответ

0

Я проверил вас проблемы со следующим кодом:

#cython: wraparound=False 
#cython: boundscheck=False 
#cython: cdivision=True 
#cython: nonecheck=False 
#cython: profile=False 

def loop(int k): 
return real_loop(k) 

def loop2(int k): 
cdef float a 
real_loop2(k, &a) 
return a 

def loop3(int k): 
    real_loop3(k) 
    return None 

def loop4(int k): 
    return real_loop4(k) 

def loop5(int k): 
cdef float a 
real_loop5(k, &a) 
return a 

cdef float real_loop(int k): 
    cdef int i 
    cdef float a 
    a = 0. 
    for i in range(k): 
     a += a**2/(a + 1) 
    return a 

cdef void real_loop2(int k, float *a): 
    cdef int i 
    a[0] = 0. 
    for i in range(k): 
     a[0] += a[0]**2/(a[0] + 1) 

cdef void real_loop3(int k): 
    cdef int i 
    cdef float a 
    a = 0. 
    for i in range(k): 
     a += a**2/(a + 1) 

cdef float real_loop4(int k): 
    cdef int i 
    cdef float a 
    a = 0. 
    for i in range(k): 
     a += a*a/(a + 1) 
    return a 

cdef void real_loop5(int k, float *a): 
    cdef int i 
    a[0] = 0. 
    for i in range(k): 
     a[0] += a[0]*a[0]/(a[0] + 1) 

где real_loop() близка к вашей функции, с измененной формулой a, так как оригинал один казалось странным.

Функция real_loop2() не возвращает никакого значения, просто обновляя a по ссылке.

Функция real_loop3() не возвращает никакой ценности.

Проверка сгенерированного C код real_loop3() можно видеть, что цикл есть, и код называется ... но у меня был тот же вывод, как @dmytro, изменение k не изменит сроки значительно ... поэтому должен быть пункт, который мне здесь не хватает.

С таймингами ниже мы можем сказать, что return не является узким местом, так как real_loop2() и real_loop5() имеют не возвращает никакого значения, и их производительность такая же, как и real_loop()real_loop4() соответственно.

In [2]: timeit _stack.loop(100000) 
1000 loops, best of 3: 1.71 ms per loop 

In [3]: timeit _stack.loop2(100000) 
1000 loops, best of 3: 1.69 ms per loop 

In [4]: timeit _stack.loop3(100000) 
10000000 loops, best of 3: 78.5 ns per loop 

In [5]: timeit _stack.loop4(100000) 
1000 loops, best of 3: 913 µs per loop 

In [6]: timeit _stack.loop5(100000) 
1000 loops, best of 3: 979 µs per loop 

Обратите внимание на ~ 2X ускорение меняется a**2 по a*a, так как a**2 требует вызова функции powf() внутри цикла.

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