使用Cython在Python中高效地进行小数组的数学运算

9
我使用numpexpr来处理大型数组的快速数学计算,但如果该数组的大小小于CPU缓存,则使用Cython编写简单的数组数学代码会更快,尤其是在多次调用函数时。
问题在于,如何在Cython中使用数组,或更明确地说:是否有一个直接的接口来连接Python的array.array类型?我想做的是这样的事情(一个简单的例子):
cpdef array[double] running_sum(array[double] arr):
    cdef int i 
    cdef int n = len(arr)
    cdef array[double] out = new_array_zeros(1.0, n)
    ... # some error checks
    out[0] = arr[0]
    for i in xrange(1,n-1):
        out[i] = out[i-1] + arr[i]

    return(out)

我最初尝试使用Cython numpy包装器并使用ndarrays,但对于小的1D数组来说,创建它们似乎非常昂贵,与使用malloc创建C数组相比(但内存处理变得麻烦)。

谢谢!


你应该将这个问题分成两个独立的部分,因为每个部分都是不同的。这样可以确保答案清晰地与特定的问题相关联,并增加用户在将来参考此问题及其答案时的可读性。 - JoshAdel
谢谢。将问题分成两部分 - 第二部分:https://dev59.com/NlXTa4cB1Zd3GeqP01_O - chronos
是的,numpy 的新数组比 malloc 慢;但是你真的需要经常创建 / 删除它们吗?你不能在开始时只创建一次 numpy 数组并重复使用它们吗?此外,对上述方法和 np.cumsum 进行 timeit 可能会很有用(什么是“小”——10、100?)。 - denis
1
为了纪念,我在这里回答了一个非常类似的问题这里。最近的Cython(0.17+)有很多好功能,可以用于处理数组、numpy.ndarrays和支持缓冲区接口的其他所有内容。 - John Tyree
1个回答

5

您可以使用基本的函数和检查来创建自己的简单版本,这里是一个模型可供参考:

from libc.stdlib cimport malloc,free

cpdef class SimpleArray:
    cdef double * handle
    cdef public int length
    def __init__(SimpleArray self, int n):
        self.handle = <double*>malloc(n * sizeof(double))
        self.length = n
    def __getitem__(self, int idx):
        if idx < self.length:
            return self.handle[idx]
        raise ValueError("Invalid Idx")
    def __dealloc__(SimpleArray self):
        free(self.handle) 

cpdef SimpleArray running_sum(SimpleArray arr):
    cdef int i 
    cdef SimpleArray out = SimpleArray(arr.length)

    out.handle[0] = arr.handle[0]
    for i from 1 < i < arr.length-1:
        out.handle[i] = out.handle[i-1] + arr.handle[i]
    return out

可以用作

>>> import test
>>> simple = test.SimpleArray(100)
>>> del simple
>>> test.running_sum(test.SimpleArray(100))
<test.SimpleArray object at 0x1002a90b0>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接