因为我发现内存视图方便快捷,所以我尽量避免在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
侧写告诉我,这里有一些速度
我能做的就是调整函数,因为有时候,比如这个向量的平均值被计算出来,有时候是求和。所以我可以重写它,用来求和或取平均值。但是,有没有一种方法可以直接创建内存视图,并动态定义大小。类似于首先创建一个c缓冲区使用malloc
等,并在函数结束时将缓冲区转换为视图,传递指针和步幅等等。
- 编辑1:**也许对于简单的情况,调整函数e。这是一个可以接受的方法。我只添加了一个参数和求和/取平均值。这样我就不必创建一个数组,并且可以在函数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
4条答案
按热度按时间sycxhyv71#
不知道如何处理cpython数组,所以我最终通过自制的“内存视图”as proposed by fabrizioM解决了这个问题。没想到这会有用在紧密循环中创建一个新的np.array是非常昂贵的,所以这给了我一个显著的加速。因为我只需要一个一维数组,我甚至不需要费心去大步。但即使对于更高维的数组,我认为这也会很好。
3okqufwl2#
Cython邮件列表中的以下主题可能会引起您的兴趣:
https://groups.google.com/forum/#!topic/cython-users/CwtU_jYADgM
看起来有一些不错的选择,如果你可以从你的函数中返回一个内存视图,这个视图在性能不是问题的不同级别上被强制。
o2g1uqev3#
从http://docs.cython.org/src/userguide/memoryviews.html可以看出,cython内存视图的内存可以通过以下方式分配:
或由
这两种情况都可以,但首先我有一个问题,如果引入自己的类型(ctypedef一些mytype),因为没有合适的格式。在第二种情况下,内存的释放存在问题。
根据手册,其工作原理如下:
它将释放内存的函数绑定到memoryview,然而该代码不编译。
66bbxpm54#
受@embert的“内存视图”Vector类型的启发,这里有一个类似的Matrix“内存视图”类型,用于存储2D数组数据。