python - cython中的缓慢 split

标签 python cython

为了在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 函数。这大大减少了传递和返回参数的开销。我还更改了 example1example2 以仅计算 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/

相关文章:

python - 如何在文件夹中导入python文件?

cython - 在 Cython 中将结构自动转换为字典

python - 使用cython编译所需的外部模块

ipython - cython在jupyter笔记本中

python - python 中 C++ vector 的实例(对于 pyROOT 中的 TTrees)

python - Pyinstaller: 无法打开共享对象 libpython3.5m.so.1.0

Python 编程。访问 Windows 右键菜单选项

Python三元运算顺序

python - 自动检测文件扩展名

python-3.x - cython可以用icc编译吗?