如何在Cython中列出内存视图?

时间:2019-07-06 16:23:33

标签: python cython memoryview

我的函数接收一系列不同大小的numpy数组:

def function1(list list_of_numpy_arrays):

现在我正在做

cdef int[:] a_view = list_of_numpy_arrays[index]

问题是我必须索引列表很多次,因此开销大大增加了时间(10x)。我正在寻找类似cdef int[:] a[5]的东西,在这里可以有一个内存视图数组,这样可以避免索引python列表的开销。

如果有解决方案,我也可以传递列表列表。

def function2(list list_of_lists):

1 个答案:

答案 0 :(得分:3)

在Cython中,您真正追求的是不可能的。如果您想要性能良好的东西,我可能会创建一个C结构,其中包含来自memoryview的相关信息,然后使用它。这不是一个非常优雅的解决方案,但是它将提供与使用memoryviews类似的性能。我不建议将其设置为通用模式,但是如果您遇到数据需要一次性输入的问题,那就可以了。

cdef struct FakeMemoryView:
    int* data
    int stride
    int length

如果您准备强制执行C个连续的记忆视图(int[::1]),则可以放弃stride,因为它被认为是一个。可以使用var.data[i*var.stride]为数据建立索引。在函数开始时,您遍历Python列表以创建包含这些FakeMemoryView的数组,然后从这一点开始,您只需使用以下数组:

def function1(list list_of_numpy_arrays):
    assert len(list_of_numpy_arrays) == 5

    cdef FakeMemoryView new_list[5]

    # initialize the list
    cdef int[:] mview
    for i in range(5):
        mview = list_of_numpy_arrays[i]
        new_list[i].data = &mview[0]
        new_list[i].stride = mview.strides[0]
        new_list[i].length = mview.shape[0]

    # example access - zero the first lot of data
    for i in range(new_list[0].length):
        new_list[0].data[i*new_list[0].stride] = 0

如果您事先不知道列表的长度,则需要使用mallocfree自己处理列表的内存。

此解决方案不处理对Numpy数组进行引用计数的操作-因此,在保存FakeMemoryView时,您不应允许Numpy数组被释放。不要在数组中存储多个函数调用,也不要从输入列表中删除数组。