为什么cffi比numpy快得多?

Tim*_*Tim 13 c python pypy numpy python-cffi

我一直在玩python中编写cffi模块,他们的速度让我想知道我是否正确使用标准python.这让我想彻底切换到C!说实话,有一些伟大的python库我永远无法在C中重新实现自己,所以这比任何事情都更加假设.

这个例子显示了python中的sum函数与numpy数组一起使用,以及与ac函数相比有多慢.是否有更快的pythonic方法来计算numpy数组的总和?

def cast_matrix(matrix, ffi):
    ap = ffi.new("double* [%d]" % (matrix.shape[0]))
    ptr = ffi.cast("double *", matrix.ctypes.data)
    for i in range(matrix.shape[0]):
        ap[i] = ptr + i*matrix.shape[1]                                                                
    return ap 

ffi = FFI()
ffi.cdef("""
double sum(double**, int, int);
""")
C = ffi.verify("""
double sum(double** matrix,int x, int y){
    int i, j; 
    double sum = 0.0;
    for (i=0; i<x; i++){
        for (j=0; j<y; j++){
            sum = sum + matrix[i][j];
        }
    }
    return(sum);
}
""")
m = np.ones(shape=(10,10))
print 'numpy says', m.sum()

m_p = cast_matrix(m, ffi)

sm = C.sum(m_p, m.shape[0], m.shape[1])
print 'cffi says', sm
Run Code Online (Sandbox Code Playgroud)

只是为了显示功能的工作原理:

numpy says 100.0
cffi says 100.0
Run Code Online (Sandbox Code Playgroud)

现在,如果我计算这个简单的功能,我发现numpy真的很慢!我是否以正确的方式使用numpy?有没有更快的方法来计算python中的总和?

import time
n = 1000000

t0 = time.time()
for i in range(n): C.sum(m_p, m.shape[0], m.shape[1])
t1 = time.time()

print 'cffi', t1-t0

t0 = time.time()
for i in range(n): m.sum()
t1 = time.time()

print 'numpy', t1-t0
Run Code Online (Sandbox Code Playgroud)

时间:

cffi 0.818415880203
numpy 5.61657714844
Run Code Online (Sandbox Code Playgroud)

Dav*_*dmh 14

Numpy比C慢,原因有两个:Python开销(可能类似于cffi)和普遍性.Numpy旨在以一堆不同的数据类型处理任意维度的数组.您的cffi示例是针对2D浮点数组生成的.成本是编写几行代码vs .sum()6个字符以节省不到5微秒.(但当然,你已经知道了这一点).我只想强调CPU时间便宜,比开发人员时间便宜得多.

现在,如果你想坚持Numpy,并希望获得更好的性能,那么你最好的选择就是使用Bottleneck.它们提供了一些针对浮动和双打的1和2D阵列进行了优化的功能,并且它们非常快速.在你的情况下,快16倍,这将使执行时间为0.35,或大约是cffi的两倍.

对于瓶颈没有的其他功能,您可以使用Cython.它可以帮助您使用更加pythonic语法编写C代码.或者,如果您愿意,可以逐步将Python转换为C,直到您对速度感到满意为止.

  • 请注意,如果直接使用瓶颈的专用功能,相对于Numpy,加速速度最高可达25倍.你的cffi现在在哪里?:) (2认同)