Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在不复制的情况下将C数组绑定到Numpy数组_Python_C_Arrays_Numpy_Cython - Fatal编程技术网

Python 在不复制的情况下将C数组绑定到Numpy数组

Python 在不复制的情况下将C数组绑定到Numpy数组,python,c,arrays,numpy,cython,Python,C,Arrays,Numpy,Cython,我正在编写一个Python类,它将封装一个包含C结构的C模块。我使用的是Cython语言(Python和C的一种超集语言)。C结构在构造函数中是malloc'd的,它包含一个我想在Python中使用的数组。该数组将在Python中表示为NumPy数组,但我不想将值复制到该数组中。我想将NumPy数组直接链接到malloc的内存。对于此任务,我使用,特别是此函数: PyObject*(int-nd,npy\u-intp*dims,int-typenum,void*data) 我在Cython中使用

我正在编写一个Python类,它将封装一个包含C结构的C模块。我使用的是Cython语言(Python和C的一种超集语言)。C结构在构造函数中是malloc'd的,它包含一个我想在Python中使用的数组。该数组将在Python中表示为NumPy数组,但我不想将值复制到该数组中。我想将NumPy数组直接链接到malloc的内存。对于此任务,我使用,特别是此函数:

PyObject*
(int-nd,npy\u-intp*dims,int-typenum,void*data)

我在Cython中使用此代码成功地将NumPy数组绑定到C结构的数组,只要NumPy数组和
MultimediaParams
对象具有相同的生存期,它就可以正常工作:

cdef class MultimediaParams:
    def __init__(self, **kwargs):
        self._mm_np = < mm_np *> malloc(sizeof(mm_np))
        #some code...

    def as_ndarray(self): #TODO: what if self deallocated but numpy array still exists(segfault?)
        cdef numpy.npy_intp shape[1]
        cdef int arr_size = sizeof(self._mm_np[0].n2) / sizeof(self._mm_np[0].n2[0])
        shape[0] = < numpy.npy_intp > arr_size
        cdef numpy.ndarray ndarray
        ndarray = numpy.PyArray_SimpleNewFromData(1, shape, numpy.NPY_DOUBLE, self._mm_np[0].n2)

        return ndarray

    def __dealloc__(self):
        free(self._mm_np)
cdef类多媒体参数:
定义初始(自我,**kwargs):
self._-mm\u-np=malloc(sizeof(mm\u-np))
#一些代码。。。
def as_ndarray(self):#TODO:如果self已解除分配但numpy数组仍然存在(segfault?),该怎么办
cdef numpy.npy_intp形状[1]
cdef int arr_size=sizeof(self._mm_np[0].n2)/sizeof(self._mm_np[0].n2[0])
形状[0]=arr\u大小
cdef numpy.ndarray ndarray
ndarray=numpy.PyArray\u SimpleNewFromData(1,shape,numpy.NPY\u DOUBLE,self.\u mm\u np[0].n2)
回程线
def uu dealoc uu(自我):
免费(自助)
如您所见,该类有其
\uuuuu dealloc\uuuu
方法,该方法将处理在C中分配的内存,并在没有对
MultimediaParams
实例的引用时释放它

在这种绑定中,NumPy不拥有数组的内存

问题:解除分配
MultimediaParams
对象并释放阵列内存时,NumPy对象仍指向刚刚释放的内存。当NumPy对象试图访问/修改已释放的内存时,这将导致segfault

只要有一个NumPy对象在使用它的内存,我如何确保没有解除分配
MultimediaParams
对象

据我所知,我所需要做的就是使NumPy对象具有对
MultimediaParams
实例的引用,它从中获得了指向该实例的内存。 我试图使用
ndarray.base=self
以便NumPy知道它的base对象,这应该是向
MultimediaParams
实例添加另一个引用,并且只要NumPy数组处于活动状态,就不会释放它。这一行导致我的测试失败,因为NumPy数组的内容变成了垃圾

澄清NumPy数组不拥有C数组内存,我不希望它拥有。我希望
MultimediaParams
负责释放C结构(包含数组数据),但只要NumPy对象处于活动状态,就不这样做


有什么建议吗?

正如@J.F.Sebastian的评论所指出的,问题很可能是,当您正确地将指向
MultimediaParams
实例的指针分配给NumPy数组的
base
引用时,实际上并没有增加它的引用计数,因为分配是在C中进行的,而不是在Python中。这可能会导致
MultimediaParams
对象过早地进行垃圾收集,该对象的内存被重用,并导致数据阵列中出现垃圾数据


使用宏
Py_incremf
手动增加
MultimediaParams
对象的引用计数应该会产生所需的行为。

与标题相关:@DavidW:它看起来不像是重复的。强制内存所有权可能会导致双重
free()
,这是不好的。OPs的问题是,如果在
.base
赋值之后发生什么?@J.F.Sebastian我认为OP真正想要解决的问题是确保内存与数组具有相同的生存期(并试图通过将其绑定到
MultimediaParams
的实例来解决)。但是他们可能有其他原因来链接这两个实例-在这种情况下,我错了,它不是重复的…@DavidW:PyArray_enablefaglass(ndarray,np.NPY_OWNDATA)如何保持
多媒体参数
实例的活动状态?好的,但问题是:Py_INCREF如何知道ndarray对象将具体指向该MultimediaParams对象?Python跟踪对象的引用数,这称为引用计数。它不需要知道哪些引用。每当创建对对象的引用时,该对象的引用计数都会增加,反之,当删除引用时,该对象的引用计数会减少。您可以通过设置ndarray的base属性来创建引用,但这是在C中完成的,在C中Python不会为您增加MultimediaParams对象的引用计数器,因此需要手动执行。