为了在cython中获得快速划分,我可以使用编译器指令
@cython.cdivision(True)
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为得到的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)
Run Code Online (Sandbox Code Playgroud)
这导致输出:
With c division: 0.000194787979126
Without c division: 0.000176906585693
Run Code Online (Sandbox Code Playgroud)
是否有任何理由为什么关闭零分割检查会减慢事情(我知道没有零除数).
小智 12
首先,您需要多次调用函数(> 1000),并平均花费在每个函数上的时间,以准确了解它们的不同之处.每次调用每个函数都不够准确.
其次,在函数中花费的时间将受到其他事物的影响,而不仅仅是具有分割的循环.调用这样的defPython函数涉及传递和返回参数的一些开销.此外,在函数中创建一个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)
Run Code Online (Sandbox Code Playgroud)
我通过探查器(python -m cProfile -s累积)运行此代码,相关输出如下:
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)
Run Code Online (Sandbox Code Playgroud)
这表明example2慢得多.如果我在example2中打开c-division,那么对于example1和example2花费的时间是相同的,所以这显然具有显着的效果.