【发布时间】:2014-10-07 08:44:55
【问题描述】:
我刚刚开始尝试使用 cython,作为第一个练习,我创建了以下(重新)实现的函数,用于计算数组中每个元素的 sin。所以这是我的 sin.pyx
from numpy cimport ndarray, float64_t
import numpy as np
cdef extern from "math.h":
double sin(double x)
def sin_array(ndarray[float64_t, ndim=1] arr):
cdef int n = len(arr)
cdef ndarray h = np.zeros(n, dtype=np.float64)
for i in range(n):
h[i] = sin(arr[i])
return h
我还为此创建了以下 setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy
ext = Extension("sin", sources=["sin.pyx"])
setup(ext_modules=[ext],
cmdclass={"build_ext": build_ext},
include_dirs=[numpy.get_include()])
所以这会创建我的 *.so 文件。我将它导入 python 并创建 1000 个随机数,例如
import sin
import numpy as np
x = np.random.randn(1000)
%timeit sin.sin_array(x)
%timeit np.sin(x)
Numpy 以 3 倍的优势获胜。这是为什么呢?我认为对输入数组的类型和维度做出非常明确的假设的函数在这里可能更具竞争力。当然,我也知道 numpy 非常聪明,但我很可能在这里做了一些愚蠢的事情......
请注意,本练习的重点不是重写更快的 sin 函数,而是为我们的一些内部工具创建一些 cython 包装器,但这是稍后的另一个问题......
【问题讨论】:
-
您的 Cython 代码中还没有边界检查等吗?在documentation example 中,他们会在某个时候将其关闭。
-
是的,我现在已经包含了。只有非常小的改进。仍然几乎是 3 倍...
-
numpy.zeros是一种糟糕的内存分配方式。至少使用numpy.empty。 -
@tschm
NumPy的正弦函数可能是矢量化的,其中整个数组只调用一个函数,而在 Cython 例程中,每个数组元素都需要一个函数调用......