我尝试在Cython上的numpy数组中转换C double *,但是我还没有成功。 我发现这些有用的链接: Force NumPy ndarray to take ownership of its memory in Cython https://github.com/numpy/numpy/issues/8253
但是每次我将以下.pyx文件与Cython一起使用时,都会使Jupyter崩溃(死的内核):
.c文件:
#include<stdlib.h>
#include "test.h"
double* test1(int n) {
double* A=(double*)calloc(n,sizeof(double));
int i;
for (i=0;i<n;i++) {
A[i]=i+0.5; }
return(A); }
我也尝试使用具有相同结果的malloc。
.pyx文件:
cimport c_test
import numpy as np
cimport numpy as np
np.import_array()
ctypedef np.float64_t DTYPE_t
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(np.ndarray arr, int flags)
cdef data_to_numpy_array_with_spec(void * ptr, np.npy_intp N, int t):
cdef np.ndarray[DTYPE_t, ndim=1] arr = np.PyArray_SimpleNewFromData(1, &N, t, ptr)
PyArray_ENABLEFLAGS(arr, np.NPY_OWNDATA)
return arr
def test(n):
cdef double* t1
t=data_to_numpy_array_with_spec(c_test.test1(n),n,np.NPY_FLOAT64)
return(t)
c_fct.test1函数返回n double的C double *,我想将其转换为拥有数据的numpy数组,以避免内存泄漏。没有PyArray_ENABLEFLAGS(t, np.NPY_ARRAY_OWNDATA)
行,一切正常,但是在销毁numpy数组时,内存未释放。
jupyter笔记本:
import cy_test as ct
ct.test(1000)
c_test.pxd文件:
cdef extern from "test.h":
double* test1(int n)
我的setup.py文件如下:
from setuptools import setup
from setuptools.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize
import numpy as np
ext_modules = cythonize([Extension("cy_test", ["cy_test.pyx","test.c"])])
setup(
name = 'Hello world app',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
include_dirs=[np.get_include()]
)
我认为我的问题可能来自与github链接相同的原因,但我看不到如何解决(在我的情况下,C指针已经存在,所以我认为我不能使用相同的解决方案)
我在使用Anaconda 64位的Windows 10上工作,以下是该版本的详细信息: 3.7.1(默认值,2018年12月10日,22:54:23)[MSC v.1915 64位(AMD64)]
答案 0 :(得分:2)
如您链接的Github issue中所述,NPY_OWNDATA
仅可与通过NumPy本身使用的同一分配器分配的内存一起使用。可以通过PyDataMem_*
函数访问此分配器。如果您的内存不是来自此分配器,则不能使用NPY_OWNDATA
。
不要试图强制数组获取您提供给它的任意内存的所有权。而是使用PyArray_SetBaseObject
将数组的 base 设置为知道如何执行正确清理的对象。 capsule可能是方便使用的对象。
答案 1 :(得分:0)
好的,谢谢您,我要做的就是像这样修改.pyx文件:
cimport c_test
import numpy as np
cimport numpy as np
from libc.stdlib cimport free
np.import_array()
ctypedef void (*PyCapsule_Destructor)(void*)
cdef extern from "numpy/arrayobject.h":
void* PyCapsule_GetPointer(void* capsule, const char *name)
void* PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
int PyArray_SetBaseObject(np.ndarray arr, void* obj)
cdef void capsule_cleanup(void* capsule):
cdef void *memory = PyCapsule_GetPointer(capsule, NULL)
free(memory)
def test(n):
cdef np.ndarray arr
cdef int nd = 1
cdef np.npy_intp shape[1]
shape[0] = <np.npy_intp> n
cdef double *data = c_test.test1(n)
arr = np.PyArray_SimpleNewFromData(nd, shape, np.NPY_DOUBLE, data)
cdef void* capsule = PyCapsule_New(data, NULL, capsule_cleanup)
PyArray_SetBaseObject( arr, capsule)
return(arr)