为了在cython中快速除法,我可以使用编译指令
@cython.cdivision(True)
这是可行的,因为生成的 C 代码没有零除检查。但是由于某种原因,它实际上使我的代码变慢了。这是一个例子:
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
@cython.cdivision(True)
def example1(double[:] xi, double[:] a, double[:] b, int D):
cdef int k
cdef double[:] x = np.zeros(D)
for k in range(D):
x[k] = (xi[k] - a[k]) / (b[k] - a[k])
return x
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def example2(double[:] xi, double[:] a, double[:] b, int D):
cdef int k
cdef double[:] x = np.zeros(D)
for k in range(D):
x[k] = (xi[k] - a[k]) / (b[k] - a[k])
return x
def test_division(self):
D = 10000
x = np.random.rand(D)
a = np.zeros(D)
b = np.random.rand(D) + 1
tic = time.time()
example1(x, a, b, D)
toc = time.time()
print 'With c division: ' + str(toc - tic)
tic = time.time()
example2(x, a, b, D)
toc = time.time()
print 'Without c division: ' + str(toc - tic)
这导致输出:
With c division: 0.000194787979126
Without c division: 0.000176906585693
为什么关闭零除法检查会减慢速度(我知道没有零除数)。
最佳答案
首先,您需要多次 (>1000) 次调用这些函数,并计算每次调用所用时间的平均值,以准确了解它们之间的差异。每个函数调用一次将不够准确。
其次,在函数中花费的时间会受到其他因素的影响,而不仅仅是带有除法的循环。调用 def
即像这样的 Python 函数涉及传递和返回参数的一些开销。此外,在函数中创建 numpy 数组需要时间,因此两个函数中循环的任何差异都不太明显。
最后,请参阅此处 ( https://github.com/cython/cython/wiki/enhancements-compilerdirectives ),将 c-division 指令设置为 False 会降低约 35% 的速度。考虑到其他开销,我认为这不足以显示在您的示例中。我检查了 Cython 输出的 C 代码,example2 的代码明显不同并且包含额外的零除法检查,但是当我剖析它,运行时的差异可以忽略不计。
为了说明这一点,我运行了下面的代码,我在其中获取了您的代码并将 def
函数转换为 cdef
函数,即 Cython 函数而不是 Python 函数。这大大减少了传递和返回参数的开销。我还更改了 example1 和 example2 以仅计算 numpy 数组中值的总和,而不是创建一个新数组并填充它。这意味着几乎所有花在每个函数上的时间现在都在循环中,因此应该更容易看出任何差异。我也多次运行每个函数,并将 D 变大。
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
@cython.cdivision(True)
@cython.profile(True)
cdef double example1(double[:] xi, double[:] a, double[:] b, int D):
cdef int k
cdef double theSum = 0.0
for k in range(D):
theSum += (xi[k] - a[k]) / (b[k] - a[k])
return theSum
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
@cython.profile(True)
@cython.cdivision(False)
cdef double example2(double[:] xi, double[:] a, double[:] b, int D):
cdef int k
cdef double theSum = 0.0
for k in range(D):
theSum += (xi[k] - a[k]) / (b[k] - a[k])
return theSum
def testExamples():
D = 100000
x = np.random.rand(D)
a = np.zeros(D)
b = np.random.rand(D) + 1
for i in xrange(10000):
example1(x, a, b, D)
example2(x, a, b,D)
我通过探查器 (python -m cProfile -s cumulative) 运行这段代码,相关输出如下:
ncalls tottime percall cumtime percall filename:lineno(function)
10000 1.546 0.000 1.546 0.000 test.pyx:26(example2)
10000 0.002 0.000 0.002 0.000 test.pyx:11(example1)
这表明 example2 慢得多。如果我在 example2 中打开 c-division,那么 example1 和 example2 所花费的时间是相同的,因此这显然具有显着的效果。
关于python - cython中的缓慢 split ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19537673/