Python Cython中动态数组的二维内存视图

Python Cython中动态数组的二维内存视图,python,memory,memory-management,cython,memoryview,Python,Memory,Memory Management,Cython,Memoryview,我知道这一点,但我一直在寻找一种从C数组生成2d MemoryView的更简单的方法。既然我是C和Cython noobie,谁能解释一下为什么会这样 cdef int[:, :] get_zeros(int d): # get 2-row array of zeros with d as second dimension cdef int i cdef int *arr = <int *> malloc(sizeof(int) * d) for i

我知道这一点,但我一直在寻找一种从C数组生成2d MemoryView的更简单的方法。既然我是C和Cython noobie,谁能解释一下为什么会这样

cdef int[:, :] get_zeros(int d):
    # get 2-row array of zeros with d as second dimension
    cdef int i
    cdef int *arr = <int *> malloc(sizeof(int) * d)
    for i in range(d):
        arr[i] = 0
    cdef int[:, :] arr_view
    arr_view[0, :] = <int[:d]>arr
    arr_view[1, :] = <int[:d]>arr
    return arr_view
cdefint[:,:]获取零(int d):
#获取以d作为第二维度的2行零数组
cdef int i
cdef int*arr=malloc(sizeof(int)*d)
对于范围(d)中的i:
arr[i]=0
cdef int[:,:]阵列视图
arr_视图[0,:]=arr
arr_视图[1,:]=arr
返回arr_视图
不行吗


编译时,我发现
无法将类型“int[::1]”分配给“int”
作为错误。这是否意味着2d memview被第一个assign语句折叠到1d,还是因为MemoryView需要连续块等

很明显,很难“解释为什么某些东西[…]不起作用”,因为归根结底,这只是一个本可以采取不同方式的设计决策。但是:

Cython MemoryView的设计非常愚蠢。它们所做的只是提供一些很好的语法来访问实现的东西的内存,然后再添加一点额外的语法,让您可以做一些事情,比如获取指针的一维内存视图

此外,memoryview作为一个整体包装了一些东西。创建
cdef int[:,:]arr\u视图时
在执行
arr\u视图=某些内容之前无效。尝试分配给它的一部分是无稽之谈,因为(a)它会将分配委托给它使用缓冲协议包装的东西,(b)分配的具体工作方式将取决于您包装的缓冲协议的格式。如果包装“间接”缓冲区协议对象,您所做的可能是有效的,但如果包装连续数组,则毫无意义。由于
arr\u view
可能正在包装,Cython编译器必须将其视为错误

实现缓冲协议,因此是实现这种数组的正确方法。您试图做的是从指针获取额外的语法,该语法提供了一个1D memoryview,并将其强制到2D memoryview的一部分,模糊地希望这可能会起作用。这需要很多逻辑,远远超出了Cython memoryview的设计范围


可能还有几点值得一提:

  • 指针的MemoryView不能处理指针的释放(因为他们几乎不可能再猜测你想要什么)。你必须处理好这个逻辑。如果你当前的设计有效的话,它会泄漏内存。在链接到包装类的设计中,可以在
    \uuuu dealoc\uuuu
    中实现这一点(尽管答案中没有显示),因此效果更好

  • 我个人的观点是“不规则数组”(指向指针的2D指针数组)非常糟糕。它们需要大量的分配和解除分配。有很多机会初始化它们。访问它们需要几个级别的间接寻址,因此速度很慢。唯一适合他们的是,他们用C提供了
    arr[idx1][idx2]
    语法。一般来说,我更喜欢Numpy的方法,即分配1D数组并使用形状/步幅来确定索引位置。(显然,如果您正在包装现有库,那么您可能不是您的选择…)


很明显,很难“解释为什么某些东西[…]不起作用”,因为最终这只是一个设计决策,可以采取不同的方式。但是:

Cython MemoryView的设计非常愚蠢。它们所做的只是提供一些很好的语法来访问实现的东西的内存,然后再添加一点额外的语法,让您可以做一些事情,比如获取指针的一维内存视图

此外,memoryview作为一个整体包装了一些东西。创建
cdef int[:,:]arr\u视图时
在执行
arr\u视图=某些内容之前无效。尝试分配给它的一部分是无稽之谈,因为(a)它会将分配委托给它使用缓冲协议包装的东西,(b)分配的具体工作方式将取决于您包装的缓冲协议的格式。如果包装“间接”缓冲区协议对象,您所做的可能是有效的,但如果包装连续数组,则毫无意义。由于
arr\u view
可能正在包装,Cython编译器必须将其视为错误

实现缓冲协议,因此是实现这种数组的正确方法。您试图做的是从指针获取额外的语法,该语法提供了一个1D memoryview,并将其强制到2D memoryview的一部分,模糊地希望这可能会起作用。这需要很多逻辑,远远超出了Cython memoryview的设计范围


可能还有几点值得一提:

  • 指针的MemoryView不能处理指针的释放(因为他们几乎不可能再猜测你想要什么)。你必须处理好这个逻辑。如果你当前的设计有效的话,它会泄漏内存。在链接到包装类的设计中,可以在
    \uuuu dealoc\uuuu
    中实现这一点(尽管答案中没有显示),因此效果更好

  • 我个人的观点是“不规则数组”(指向指针的2D指针数组)非常糟糕。它们需要大量的分配和解除分配。有很多机会初始化它们。访问它们需要几个级别的间接寻址,因此速度很慢。唯一适合他们的是,他们用C提供了
    arr[idx1][idx2]
    语法。一般来说,我更喜欢Numpy的方法,即分配1D数组并使用形状/步幅来确定索引位置。(显然,如果您正在包装现有库,那么您可能不是您的选择…)


    • 除了@DavidW提供的精彩答案外,我还想补充一些信息。在你包含的代码中,我看到了
      cdef int[:, :] get_zeros(int d):    
          cdef int *arr = <int *>calloc(2 * d, sizeof(int))
          cdef int[:, :] arr_view = <int[:2, :d]>arr
          return arr_view