什么是memoryview:
当你在函数中写入以下代码:
cdef double[:] a
你最终得到一个
__Pyx_memviewslice
对象:
typedef struct {
struct __pyx_memoryview_obj *memview;
char *data;
Py_ssize_t shape[8];
Py_ssize_t strides[8];
Py_ssize_t suboffsets[8];
} __Pyx_memviewslice;
The memoryview包含一个C指针和一些数据,它通常不直接拥有。它还包含一个指向底层Python对象(
struct __pyx_memoryview_obj * memview;
)的指针。如果数据由Python对象拥有,则
memview
保留对其的引用,并确保在memoryview存在时保持持有数据的Python对象存活。
指向原始数据的指针以及如何索引它的信息(
shape
、
strides
和
suboffsets
的组合)允许Cython使用原始数据指针和一些简单的C数学运算进行索引(非常高效)。例如:
x=a[0]
给出类似于:
(*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_2 * __pyx_v_a.strides[0]) )));
相比之下,如果您使用未经类型定义的对象并编写如下内容:
a = np.array([1,2,3])
x = x[0]
索引是这样完成的:
__Pyx_GetItemInt(__pyx_v_a, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1);
这本身会扩展到一堆Python C-api调用(因此很慢)。最终它会调用a
的__getitem__
方法。
与numpy数组相比:实际上并没有太大的区别。
如果你做了这样的事情:
cdef np.ndarray[np.int32_t, ndim=1] new_arr
这个功能实际上很像memoryview,可以访问原始指针,速度应该非常相似。
使用memoryview的优点是可以使用更广泛的数组类型(例如标准库数组),因此您对可以调用函数的类型更加灵活。这符合Python的一般思想:“鸭子类型”-即您的代码应该与表现正确的任何参数一起工作(而不是检查类型)。
第二个(小)优点是构建模块时不需要numpy头文件。
第三个(可能更大的)优点是内存视图可以在没有GIL的情况下初始化,而cdef np.ndarray
则不能(http://docs.cython.org/src/userguide/memoryviews.html#comparison-to-the-old-buffer-support)
内存视图的一个轻微劣势是它们似乎设置起来略慢。
与仅使用malloc
的int指针相比:
您不会获得任何速度优势(但也不会有太多速度损失)。使用memoryview进行转换的微小优势包括:
You can write functions that can be used either from Python or internally within Cython:
cpdef do_something_useful(double[:] x):
....
You can let Cython handle the freeing of memory for this type of array, which could simplify your life for things that have an unknown lifetime. See http://docs.cython.org/src/userguide/memoryviews.html#cython-arrays and especially .callback_free_data
.
You can pass your data back to python python code (it'll get the underlying __pyx_memoryview_obj
or something similar). Be very careful of memory management here (i.e. see point 2!).
The other thing you can do is handle things like 2D arrays defined as pointer to pointer (e.g. double**
). See http://docs.cython.org/src/userguide/memoryviews.html#specifying-more-general-memory-layouts. I generally don't like this type of array, but if you have existing C code that already uses if then you can interface with that (and pass it back to Python so your Python code can also use it).
memoryview
只是cython
自己的一组c
函数,用于访问缓冲区,绕过了numpy
函数。它不会比直接的c
风格访问更快,但可能更容易使用。 - hpaulj