我用以下的程式碼测试了你的问题:
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
请注意,将
a**2
更改为
a*a
会使速度提高约2倍,因为
a**2
在循环内需要调用
powf()
函数。
real_loop
不会更新任何全局变量,并且它也不会改变任何参数,因此可以被转化为无操作。 - mgilsondiff
命令来比较这两个生成的C文件之间的差异吗?可能是因为Cython认为没有return
语句的函数是无用的,并且根本没有执行这些函数。 - Bakuriu