提高Cython数组索引速度

4 投票
1 回答
1526 浏览
提问于 2025-04-18 05:53

我有一个比较简单的函数,需要让它运行得更快。基本上,我有一个包含16位数字的大数组,但里面有一些空缺(大约10%)。我需要遍历这个数组,找到连续两个0的地方,然后用前一个和后一个元素的平均值来填补这些0。在C语言中,这个过程只需要几毫秒,但在Python中就慢得多。

我把普通的Python数组换成了numpy数组,然后用cython编译了我的代码,但离我想要的速度还有很大差距。我希望有经验的人能看看我在做什么,并给我一些反馈。

我的普通Python代码是这样的:

self.rawData = numpy.fromfile(ql, numpy.uint16, 50000)
[snip]
def fixZeroes(self):
    for x in range(2,len(self.rawData)):
        if self.rawData[x] == 0 and self.rawData[x-1] == 0:
            self.rawData[x] = (self.rawData[x-2] + self.rawData[x+2]) / 2
            self.rawData[x-1] = (self.rawData[x-3] + self.rawData[x+1]) /2

我的Cython代码看起来很相似:

import numpy as np
cimport numpy as np
DTYPE = np.uint16
ctypedef np.uint16_t DTYPE_t

@cython.boundscheck(False)
def fix_zeroes(np.ndarray[DTYPE_t, ndim=1] raw):
    assert raw.dtype == DTYPE
    cdef int len = 50000
    
    for x in range(2,len):
        if raw[x] == 0 and raw[x-1] == 0:
            raw[x] = (raw[x-2] + raw[x+2]) / 2
        raw[x-1] = (raw[x-3] + raw[x+1]) /2
    return raw

当我运行这段代码时,性能仍然比我希望的要慢很多:

开始修复零值

完成:0:00:36.983681

开始Python修复零值

完成:0:00:41.434476

我真的觉得我可能做错了什么。我看到的大多数文章都在讲numpy和cython能带来巨大的性能提升,但我几乎没有超过10%的提升。

1 个回答

7

你应该先声明一下你用来索引 raw 数组的 x 变量:

cdef int x

你还可以使用其他一些指令,这些指令通常能提高性能:

@cython.wraparound(False)
@cython.cdivision(True)
@cython.nonecheck(False)

撰写回答