如何处理 cython 中 np.ndarray 的内存



例如,如果我这样做:

cdef np.ndarray[np.int64_t, ndim=1] my_array

我的my_array存放在哪里?我认为,由于我没有告诉cython存储在堆上,因此它将被存储在堆栈上,但是在进行以下实验之后,它似乎存储在堆上,或者以某种方式有效地管理内存。如何管理my_array内存?也许我错过了一些明显的东西,但我找不到任何文档。

import numpy as np
cimport cython
cimport numpy as np
from libc.stdlib cimport malloc, free
def big_sum():
    # freezes up:
    # "a" is created on the stack
    # space on the stack is limited, so it runs out
    cdef int a[10000000]
    for i in range(10000000):
        a[i] = i
    cdef int my_sum
    my_sum = 0
    for i in range(10000000):
        my_sum += a[i]
    return my_sum
def big_sum_malloc():
    # runs fine:
    # "a" is stored on the heap, no problem
    cdef int *a
    a = <int *>malloc(10000000*cython.sizeof(int))
    for i in range(10000000):
        a[i] = i
    cdef int my_sum
    my_sum = 0
    for i in range(10000000):
        my_sum += a[i]
    with nogil:
        free(a) 
    return my_sum    
def big_numpy_array_sum():
    # runs fine:
    # I don't know what is going on here
    # but given that the following code runs fine,
    # it seems that entire array is NOT stored on the stack
    cdef np.ndarray[np.int64_t, ndim=1] my_array
    my_array = np.zeros(10000000, dtype=np.int64)
    for i in range(10000000):
        my_array[i] = i
    cdef int my_sum
    my_sum = 0
    for i in range(10000000):
        my_sum += my_array[i]
    return my_sum

Cython在这里并没有做任何神奇的事情。Numpy 有一个完整的 C-api,这就是 cython 与之交互的内容——cython 本身不执行内存管理,numpy 数组中的内存处理方式与使用 python 的 numpy 数组时相同。@Bakuriu是对的 - 这绝对是堆。

考虑这个密码代码:

cimport numpy as np
def main():
    zeros = np.zeros
    cdef np.ndarray[dtype=np.double_t, ndim=1] array
    array = zeros(10000)

这将在等效的主函数中转换为以下 C。我删除了声明和错误处理代码,使其更易于阅读。

PyArrayObject *__pyx_v_array = 0;
PyObject *__pyx_v_zeros = NULL;
PyObject *__pyx_t_1 = NULL;
PyObject *__pyx_t_2 = NULL;
// zeros = np.zeros             # <<<<<<<<<<<<<<
// get the numpy module object
__pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s__np);
// get the "zeros" function
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s__zeros)
__pyx_v_zeros = __pyx_t_2;
// array = zeros(10000)             # <<<<<<<<<<<<<<
// (__pyx_k_tuple_1 is a static global variable containing the literal python tuple
// (10000, ) that was initialized during the __Pyx_InitCachedConstants function)
__pyx_t_2 = PyObject_Call(__pyx_v_zeros, ((PyObject *)__pyx_k_tuple_1), NULL);
__pyx_v_array = ((PyArrayObject *)__pyx_t_2);

如果你查找numpy C api文档,你会看到PyArrayObject是numpy。ndarray 的 C-api 结构体。这里的关键点是看到cython根本没有显式处理内存分配。相同的面向对象设计原则适用于python和numpy C API,这里的内存管理由PyArrayObject负责。这种情况与在 python 中使用 numpy 数组没有什么不同。

最新更新