2013-02-08 66 views
3

我有這樣的用Cython代碼只是爲了測試:低速時return語句

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 

我測試在純Python這種用Cython代碼和相同的代碼之間的速度diffence有了這樣的腳本:

import mymodule 

print(mymodule.loop(100000)) 

我快了80倍。但是,如果我刪除了cython代碼中的兩個return語句,我會快800-900倍。爲什麼?

另一個事情是,如果我在我的舊宏碁Aspire One筆記本電腦運行這段代碼(有回報)我得到700times更快,在家裏一個新的桌面i7的電腦,80times快上。

有人知道爲什麼嗎?

+4

這很難說 - 我不知道如果編譯器將足夠聰明地看到,'real_loop'不更新任何全局變量,它不會改變任何的參數,因此它可以變成一個沒有-OP。 – mgilson 2013-02-08 15:15:04

+1

您是否嘗試對兩個生成的C文件進行「差異化」以查看差異?無論如何,也許是因爲cython認爲沒有'return'的函數是無用的,並且完全循環。 – Bakuriu 2013-02-08 15:49:27

+1

@Bakuriu是的,這是我的想法。可能根本不做循環。我不知道如何,但昨天當我嘗試不同的方式來編碼時,我得到了一些可笑的表現,比如12000倍的速度。 – 2013-02-08 16:02:53

回答

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()沒有返回任何值。

檢查real_loop3()一個生成的代碼C可以看到,循環是存在的,並且代碼被稱爲...但我有同樣的結論爲@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 

注意〜2倍加速改變由a*aa**2,因爲a**2需要一個函數調用powf()內循環。