【发布时间】:2014-08-10 02:06:51
【问题描述】:
考虑以下 Cython 代码:
cimport cython
cimport numpy as np
import numpy as np
@cython.boundscheck(False)
@cython.wraparound(False)
def test_memoryview(double[:] a, double[:] b):
cdef int i
for i in range(a.shape[0]):
a[i] += b[i]
@cython.boundscheck(False)
@cython.wraparound(False)
def test_numpy(np.ndarray[double, ndim=1] a, np.ndarray[double, ndim=1] b):
cdef int i
for i in range(a.shape[0]):
a[i] += b[i]
def test_numpyvec(a, b):
a += b
def gendata(nb=40000000):
a = np.random.random(nb)
b = np.random.random(nb)
return a, b
在解释器中运行它会产生(经过几次运行以预热缓存):
In [14]: %timeit -n 100 test_memoryview(a, b)
100 loops, best of 3: 148 ms per loop
In [15]: %timeit -n 100 test_numpy(a, b)
100 loops, best of 3: 159 ms per loop
In [16]: %timeit -n 100 test_numpyvec(a, b)
100 loops, best of 3: 124 ms per loop
# See answer below :
In [17]: %timeit -n 100 test_raw_pointers(a, b)
100 loops, best of 3: 129 ms per loop
我尝试了不同的数据集大小,并且始终让矢量化 NumPy 函数比编译后的 Cython 代码运行得更快,而我期望 Cython 在性能方面与矢量化 NumPy 相当。
我是否忘记了 Cython 代码中的优化? NumPy 是否使用某些东西(BLAS?)来使这些简单的操作运行得更快?我可以提高这段代码的性能吗?
更新:原始指针版本似乎与 NumPy 相当。因此,使用内存视图或 NumPy 索引显然存在一些开销。
【问题讨论】:
-
10 次循环:您真的只运行了 10 次性能测试以获得平均值吗?如果是这样,那么正常方差可能会大于您尝试测量的值。改为尝试 100000 次。
-
这是 Python 2.x 吗?如果是这样,
range可能会造成一些差异 -
@AaronDigulla :我用 100 次运行的时间更新了问题
-
@MrE:我的印象是 Cython 自动将
range的使用转换为 C 循环。我错了吗? -
根据您的硬件和 numpy 版本,一些基本的数学运算可能使用 SSE2 指令,因此使用
double运行速度比普通版快两倍,或者使用float快 4 倍C/Cython 实现。
标签: python arrays performance numpy cython