那是一个相当复杂的问题!有一些方面需要考虑。
速度:
让我们从一个简单的
int
-缓冲区(我跳过了不必要的
&c_buffer[0]
-业务):
%%cython
cdef class CMyClass:
cdef int c_buffer[1000]
def get_array(self):
return <int[:1000]>self.c_buffer
def get_memoryview(self):
return memoryview(<int[:1000]>self.c_buffer)
“类型化内存视图”在cython中有些不透明,有些类非常相似,根据函数的签名从函数返回:
但是,上面这些都不是您在第二个函数中返回的memory视图:它返回
Python's memoryview
是的。
相当混乱!就我个人而言,我保持简单,相信cython会返回最合适的类——对我来说,它只是一个缓冲。
当我们测量速度时,第一个版本会更快,因为将ARYAYOBO封装到Python的内存视图中只会增加复杂性:
>>>c=CMyClass()
>>>%timeit c.get_array()
377 ns ± 1.69 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>>%timeit c.get_memoryview()
561 ns ± 2.31 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
生命周期:
记忆来自
c_buffer
未复制:
>>>c=CMyClass()
>>>c.get_array()[0]=42
>>>print(c.get_memoryview()[0])
听起来是好事,其实不是!问题是:
C U缓冲器
不是python对象,当它超出作用域时,内存视图的数据指针将变得悬空:
>>c=CMyClass()
>>>c.get_array()[0]=42
>>>c=c.get_array() # old c-object is now destroyed
>>>print(c[0]) # anything can happen!
-304120624
我很幸运,python没有崩溃,但它可以,因为绑定之后
c
对于memoryView,底层对象被销毁,内存被释放。
使用
std::vector
在那里帮不了你。您需要的是一个具有引用计数的真正python对象!例如,我们可以使用cython的数组:
%%cython
from cython.view cimport array as cvarray
cdef class CMyClass:
cdef int[:] c_buffer
def __cinit__(self):
self.c_buffer = cvarray(shape=(1000,), itemsize=sizeof(int), format="i")
def get_array(self):
cdef int[:] res=self.c_buffer # nobody needs to know which class we use
return res
现在上面的代码是安全的:
>>c=CMyClass()
>>>c.get_array()[0]=42
>>>c=c.get_array() # old c-object is now destroyed
>>>print(c[0]) # but the underlying memory is still alive
42
自定义结构:
但是海关结构呢,如上面的例子?可能最简单的方法是使用numpy:
%%cython -a
import numpy as np
cimport numpy as np
#define a type for memory view
ctypedef packed struct my_struct_t:
np.float32_t x
np.float32_t y
#define a type for numpy-array (is a python-object)
my_struct = np.dtype([
('x', np.float32, 1),
('y', np.float32, 1),
])
cdef class CMyClass:
cdef object c_buffer
def __cinit__(self):
self.c_buffer = np.empty(1000,dtype=my_struct)
def get_array(self):
cdef my_struct_t[:] res=self.c_buffer
return res
如广告所述:
>>>c=CMyClass()
>>>c.get_array()[0]={'x':42,'y':42}
>>>c=c.get_array() # old c-object is now destroyed
>>>print(c[0]) # but this is still ok
{'x': 42.0, 'y': 42.0}
还有两句话:
-
使用numpy比较慢-
get_array()
比原来慢三倍
获取数组()
版本
-
使用
my_struct_t c_buffer
这并不能真正帮助您(除了危险之外),因为没有规则如何将数据从c-struct转换为python对象,但是这个检查发生在运行时,当数组的元素被访问时。