如何在 Cython 中 return 或将大型 malloc 数组保存为 Python 对象?
How to return or save large malloc'd arrays in Cython as Python objects?
我想使用 Cython 从模型创建大量模拟样本,稍后我需要使用 Python 进行分析。我的模拟脚本的一个 运行 结果应该是一个 10000 x 10000 数组。
我使用 def
定义了一个函数,并尝试将我的数组声明为 cdef int my_array[10000][10000]
。 my_script.pyx
文件编译正确,但是当我 运行 脚本时,出现“分段错误”错误(我在 Linux)。
寻找解决方案,我了解到这个问题是由于在堆栈而不是堆上分配内存引起的,所以我决定使用 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
当我尝试编译这个文件时,我得到了一个错误 Cannot convert 'int **' to Python object
这是有道理的,因为 my_array 不是一个正确的数组所以我猜它不能被 return 编辑为Python object(抱歉,我对C的知识真的很生疏)。
有没有办法让函数 return 我的二维数组,这样它就可以用作其他 Python 函数的输入?另一个非常受欢迎的解决方案可能是直接将数组保存在一个文件中,稍后可以通过 Python 脚本导入该文件。
谢谢。
根据@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 对象并具有所有好的数组属性(如 .shape
)符合cdef np.ndarray[...
。通过使用内存视图,可以在没有 Python 交互的情况下循环遍历此数组。
我想使用 Cython 从模型创建大量模拟样本,稍后我需要使用 Python 进行分析。我的模拟脚本的一个 运行 结果应该是一个 10000 x 10000 数组。
我使用 def
定义了一个函数,并尝试将我的数组声明为 cdef int my_array[10000][10000]
。 my_script.pyx
文件编译正确,但是当我 运行 脚本时,出现“分段错误”错误(我在 Linux)。
寻找解决方案,我了解到这个问题是由于在堆栈而不是堆上分配内存引起的,所以我决定使用 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
当我尝试编译这个文件时,我得到了一个错误 Cannot convert 'int **' to Python object
这是有道理的,因为 my_array 不是一个正确的数组所以我猜它不能被 return 编辑为Python object(抱歉,我对C的知识真的很生疏)。
有没有办法让函数 return 我的二维数组,这样它就可以用作其他 Python 函数的输入?另一个非常受欢迎的解决方案可能是直接将数组保存在一个文件中,稍后可以通过 Python 脚本导入该文件。
谢谢。
根据@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 对象并具有所有好的数组属性(如 .shape
)符合cdef np.ndarray[...
。通过使用内存视图,可以在没有 Python 交互的情况下循环遍历此数组。