[英]c malloc array pointer return in cython
如何有效地将 cython 中的 malloc 数组指针(或 numpy 数组指针)返回到 python3。
只要我不返回数组指针,cython 代码就可以完美运行
我想要:
def double complex* randn_zig(int n):
...
r = malloc(n*n*sizeof(double complex))
...
return r
c11 (gcc 11) 等效项是:
double complex* randn_zig(int n){
r = malloc(n*n*sizeof(double complex))
return r
}
我试过<double complex*> randn_zig(int n):
和randn_zig(<double complex*> r, int n):
到目前为止,其他排列均未成功。 c 和 cython 代码版本比 Numby/pylab randn 版本快 5 倍,如果我能找到一种方法返回指向大型 10^6 到 10^10 双复数数组的指针的话。
你的问题与这篇文章类似。
您可以使用下面的函数将C指针传递给Numpy数组。 当Numpy阵列被回收时,内存将自动释放。 如果你想要指针释放指针,你不应该设置NPY_OWNDATA标志。
import numpy as np
cimport numpy as np
cdef pointer_to_numpy_array_complex128(void * ptr, np.npy_intp size):
'''Convert c pointer to numpy array.
The memory will be freed as soon as the ndarray is deallocated.
'''
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)
cdef np.ndarray[np.complex128, ndim=1] arr = \
np.PyArray_SimpleNewFromData(1, &size, np.NPY_COMPLEX128, ptr)
PyArray_ENABLEFLAGS(arr, np.NPY_OWNDATA)
return arr
以供参考:
当然,你也可以使用cython memoryview 。
import numpy as np
cimport numpy as np
cdef np.complex128_t[:,:] view = <np.complex128_t[:n,:n]> c_pointer
numpy_arr = np.asarray(view)
上面的代码将C指针传递给numpy数组。 然而,这不会自动释放内存,你必须自己释放内存,否则会导致内存泄漏!
另一个选项(除了顶部答案中的两个选项: PyArray_SimpleNewFromData
并且只返回类型化的内存视图而不处理内存)是使用cython.view.array
class 。
这是一个相当低级的 class,可用于包装现有的 memory。它具有一个属性callback_free_data
,您可以在其中设置 function 以在销毁时调用,以便它释放 memory(此处的示例代码是从文档中复制的) :
cdef view.array my_array = view.array(..., mode="fortran", allocate_buffer=False)
my_array.data = <char *> my_data_pointer
# define a function that can deallocate the data (if needed)
my_array.callback_free_data = free
它公开了缓冲区协议,以便您可以对其进行索引,将其与类型化的内存视图一起使用,或者使用 np.asarray 用np.asarray
数组(不复制)包装它。 后一个功能可能比PyArray_SimpleNewFromData
更容易使用。
我认为最好的方法是将通过NumPy在Python中创建的现有数组的指针传递给Cython,否则您似乎必须将malloc
创建的数组的内容复制到另一个数组,如此玩具示例中所示:
import numpy as np
cimport numpy as np
from libc.stdlib cimport malloc, free
def main():
cdef int i, n=40
cdef double complex *r
cdef np.ndarray[np.complex128_t, ndim=1] a
a = np.zeros(n*n, dtype=np.complex128)
r = <double complex *>malloc(n*n*sizeof(double complex))
for i in range(n*n):
r[i] = 1.
for i in range(n*n):
a[i] = r[i]
free(r)
return a
对于使用C-11标准的gcc 5+(gcc -std = gnu11 ...),多维malloc和calloc数组的语法已经发生了显着变化。
一个main()过程,用于为n = 1024创建一个2-D,双,复数calloc数组r [n] [n]现在:
long n = 1024;
complex double (*r)[n] = calloc(n, sizeof *r);
使用指向此calloc数组r [n] [n]的指针的高斯随机数生成器randn_box_muller()的示例是:
inline static void randn_box_muller(long n, complex double r[][n])
{
long i, j;
register double x, y;
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
x = 2.*M_PI*dsfmt_genrand_close_open(&dsfmt);
y = sqrt(-2.*log(dsfmt_genrand_close_open(&dsfmt)));
r[i][j] = (cos(x) + I*sin(x))*y;
}
}
return;
}
这个相对较新的calloc分配语法有点奇怪。 它适用于1,2和甚至n维的calloc和malloc数组。 希望这也可以与Python3一起使用。 我希望很快就能测试一下。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.