python – Cython:创建没有NumPy数组的内存视图?

由于我发现内存视图方便快捷,我尝试避免在cython中创建NumPy数组并使用给定数组的视图.但是,有时无法避免,不能改变现有阵列而是创建新阵列.在上层函数中,这是不明显的,但在经常被称为子例程的情况下.考虑以下功能

#@cython.profile(False)
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
cdef double [:] vec_eq(double [:] v1, int [:] v2, int cond):
    ''' Function output corresponds to v1[v2 == cond]'''
    cdef unsigned int n = v1.shape[0]
    cdef unsigned int n_ = 0
    # Size of array to create
    cdef size_t i
    for i in range(n):
        if v2[i] == cond:
            n_ += 1
    # Create array for selection
    cdef double [:] s = np.empty(n_, dtype=np_float) # Slow line
    # Copy selection to new array
    n_ = 0
    for i in range(n):
        if v2[i] == cond:
            s[n_] = v1[i]
            n_ += 1
    return s

剖析告诉我,这里有一定的速度

http://uppix.com/f-sil252cdaca8001511f6.png

我能做的是调整函数,有时候会导致例如计算这个向量的平均值,有时是总和.所以我可以重写它,用于求和或取平均值.但是没有办法直接创建具有非常小的开销的内存视图,动态定义大小.像首先使用malloc等创建一个c缓冲区并在函数末尾将缓冲区转换为视图,传递指针和步幅等等.

编辑1:
也许对于简单的情况,适应功能e. G.这是一种可接受的方法.我只添加了一个参数并总结/取平均值.这样我就不必创建一个数组,并且可以轻松处理内部函数malloc.这不会更快,是吗?

# ...
cdef double vec_eq(double [:] v1, int [:] v2, int cond, opt=0):
    # additional option argument
    ''' Function output corresponds to v1[v2 == cond].sum() / .mean()'''
    cdef unsigned int n = v1.shape[0]
    cdef int n_ = 0
    # Size of array to create
    cdef Py_ssize_t i
    for i in prange(n, nogil=True):
        if v2[i] == cond:
            n_ += 1
    # Create array for selection
    cdef double s = 0
    cdef double * v3 = <double *> malloc(sizeof(double) * n_)
    if v3 == NULL:
        abort()
    # Copy selection to new array
    n_ = 0
    for i in range(n):
        if v2[i] == cond:
            v3[n_] = v1[i]
            n_ += 1
    # Do further computation here, according to option
    # Option 0 for the sum
    if opt == 0:
        for i in prange(n_, nogil=True):
            s += v3[i]
        free(v3)
        return s
    # Option 1 for the mean
    else:
        for i in prange(n_, nogil=True):
            s += v3[i]
        free(v3)
        return s / n_
    # Since in the end there is always only a single double value, 
    # the memory can be freed right here
最佳答案
不知道,如何处理cpython数组,所以我最终通过自制的“内存视图”as proposed by fabrizioM来解决这个问题.不会想到这会起作用.在紧凑的循环中创建一个新的np.array非常昂贵,所以这给了我一个显着的加速.因为我只需要一维数组,所以我甚至不必费心.但即使对于更高维度的阵列,我认为这可能会很顺利.

cdef class Vector:
    cdef double *data
    cdef public int n_ax0

    def __init__(Vector self, int n_ax0):
        self.data = <double*> malloc (sizeof(double) * n_ax0)
        self.n_ax0 = n_ax0

    def __dealloc__(Vector self):
        free(self.data)

...
#@cython.profile(False)
@cython.boundscheck(False)
cdef Vector my_vec_func(double [:, ::1] a, int [:] v, int cond, int opt):
    # function returning a Vector, which can be hopefully freed by del Vector
    cdef int vecsize
    cdef size_t i
    # defs..
    # more stuff...
    vecsize = n
    cdef Vector v = Vector(vecsize)

    for i in range(vecsize):
        # computation
        v[i] = ...

    return v

...
vec = my_vec_func(...
ptr_to_data = vec.data
length_of_vec = vec.n_ax0

转载注明原文:python – Cython:创建没有NumPy数组的内存视图? - 代码日志