我知道这个问题,但我正在寻找一种从C数组生成2d内存视图的更简单的方法。既然我是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不管用吗?
在编译它时,我将Cannot assign type 'int[::1]' to 'int'作为错误。这是否意味着第一个赋值语句对1d折叠了2d memview,还是因为内存视图需要连续块等等?
发布于 2019-10-31 11:01:53
很明显,很难“解释为什么某件事情.不起作用”,因为最终这只是一个可以采取不同方式的设计决策。但是:
Cython内存视图被设计成相当愚蠢。他们所做的就是提供一些很好的语法来访问实现Python缓冲协议的东西的内存,然后有一些额外的语法让您可以得到指针的一维内存视图。
此外,内存视图作为一个整体包装了一些东西。创建cdef int[:, :] arr_view时,在执行arr_view = something之前它是无效的。试图分配给它的一部分是无稽之谈,因为(a)它将分配委托给它使用缓冲区协议包装的东西,(b)分配的确切方式将取决于您包装的缓冲区协议的格式。如果包装一个“间接”缓冲区协议对象,您所做的工作可能是有效的,但是如果包装一个连续的数组,则没有意义。由于arr_view可能正在包装,所以Cython编译器必须将其视为一个错误。
你所链接到的问题实现了缓冲协议,因此是实现这种数组的正确方法。你想要做的是从指针中获得一个一维内存视图的额外语法,并将它强制进入一个2D内存视图的一部分,从而模糊地希望这可能会奏效。这需要大量的逻辑,这些逻辑远远超出了Cython内存视图设计的范围。
也许还有几点值得提出来:
__dealloc__中实现这一点(尽管答案中没有显示),因此更好。arr[idx1][idx2]语法。一般来说,我更喜欢Numpy的方法,它分配一维数组,并使用for /量程来确定索引的位置。(显然,如果您正在包装一个现有的库,那么您可能不是您的选择.)发布于 2019-10-31 21:21:50
除了@DavidW提供的精彩答案之外,我还想添加一些更多的信息。在您包含的代码中,我看到您正在malloc-正在处理一个In数组,然后在for-循环中将内容归零。一种更方便的方法是使用C的calloc函数,它保证指向零内存的指针,之后不需要for循环。
此外,您还可以创建一个int *,它指向一个数据的“数组”,该数组的总大小为2*d* size of (Int)。这将确保数据的“行”彼此相连,而不是分开和粗糙。然后可以直接将其转换到2d内存视图中。
正如注释中所承诺的,下面是转换代码的样子(包括calloc的使用):
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如果您想尝试一下,每个文档的python中似乎也有一个钙当量。但是,它似乎没有被包装。在cython的mem.pxd模块中,这就是为什么您可能找不到它的原因。您可以在代码中声明一个类似的extern块来包装它,就像包含在该链接中的其他函数一样。
如果您想了解更多关于编写分配器以从大块中分配内存的知识,下面是一个奖金环节 (例如,PyMem_*函数可能在幕后做什么,但在特定用例的可调和控制下)。
https://stackoverflow.com/questions/58624047
复制相似问题