如何在Cython中将大型malloc'd数组返回或保存为Python对象?

How to return or save large malloc'd arrays in Cython as Python objects?

提问人:Emalude 提问时间:10/26/2021 最后编辑:feetwetEmalude 更新时间:9/18/2023 访问量:307

问:

我想使用 Cython 从模型创建大量模拟样本,稍后需要使用 Python 进行分析。运行一次模拟脚本的结果应该是 10000 x 10000 数组。

我已经定义了一个函数,并试图将我的数组声明为 .文件编译正确,但是当我运行脚本时,我遇到了“分段错误”错误(我在Linux上)。defcdef int my_array[10000][10000]my_script.pyx

在寻找解决方案时,我了解到这个问题是由在堆栈而不是堆上分配内存引起的,所以我决定使用它来分配内存。这是我尝试执行的操作的最低版本:PyMem_Malloc

import cython
from cpython.mem cimport PyMem_Malloc
from libc.stdlib cimport rand, srand, RAND_MAX

srand(time(NULL))

def my_array_func(int a_param)
    cdef int i
    cdef int **my_array = <int **>PyMem_Malloc(sizeof(int *) * 10000)
    for i in range(10000):
        my_array[i] = <int *>PyMem_Malloc(sizeof(int) * 10000)
    
    cdef int j
    cdef int k
    for j in range(10000):
        for k in range(10000):
            my_array[j][k] = <float>rand()/RAND_MAX * a_param
    
    return my_array

当我尝试编译这个文件时,我得到了一个错误,这是有道理的,因为my_array不是一个正确的数组,所以我想它不能作为 Python 对象返回(对不起,我对 C 的了解真的很生疏)。Cannot convert 'int **' to Python object

有没有办法让函数返回我的 2D 数组,以便它可以用作其他 Python 函数的输入?另一个更受欢迎的解决方案可能是直接将数组保存在一个文件中,稍后可以通过 Python 脚本导入该文件。

python 多维数组 malloc cython 大数据

评论

0赞 hpaulj 10/26/2021
你说的是什么样的python对象??其他常见的 python 类是 、 、 。还有一个泛型类,但它没有任何(许多)定义的方法。numpy.ndarrayintlistdictobject
0赞 Emalude 10/26/2021
该数组包含相同类型的数字,因此或同样有效。但是,我发现的唯一解决方案意味着遍历指针的my_array指针,并一次将一个值分配给 python 对象,这让我回到了最初的问题(堆栈上的内存和分段错误错误)。numpy.ndarraylist
2赞 DavidW 10/26/2021
为什么不直接使用 10000 x 10000 numpy 数组而不是错位的 C 数组呢?

答:

2赞 ibarrond 10/27/2021 #1

根据 @DavidW 的评论,当 Cython 涉及矩阵计算时,建议使用 numpy 数组来拥有内存并生活在 pythonland 中。

在您的例子中,它看起来像这样:

import cython
cimport numpy as np
import numpy as np
from libc.stdlib cimport rand, srand, RAND_MAX
from libc.time cimport time

srand(time(NULL))

def my_array_func(int a_param):
    cdef int n_rows=10000, ncols=10000
    # Mem alloc + Python object owning memory
    cdef np.ndarray[dtype=int, ndim=2] my_array = np.empty((n_rows,ncols), dtype=int)

    # Memoryview: iterate over my_array at C speed
    cdef int[:,::1] my_array_view = my_array 

    # Fill array
    cdef int i, j
    for i in range(n_rows):
        for j in range(ncols):
            my_array_view[i,j] = <int> (rand()/RAND_MAX * a_param)
    
    return my_array

分配一个定义大小的空内存块,确保它归 Python 对象所有并具有所有漂亮的数组属性(如 ),这是您在一行中得到的。通过使用 memoryview,可以在没有 Python 交互的情况下完成此数组的循环。.shapecdef np.ndarray[...