Gio*_*ker 15 python arrays cython memoryview
Cython 文档很好地解释了它们允许的内容,如何声明它们以及如何使用它们.
但是,我仍然不清楚他们到底是什么.例如,来自numpy数组的简单赋值如下:
my_arr = np.empty(10, np.int32)
cdef int [:] new_arr = my_arr
Run Code Online (Sandbox Code Playgroud)
可以使访问/分配my_arr更快.
幕后发生了什么?Numpy应该已经以连续的方式在内存中分配元素了,那么内存视图的处理是什么?显然不是那么多,实际上numpy数组的memoryview赋值new_arr应该相当于
cdef np.ndarray[np.int32_t, ndim=1] new_arr = np.empty(10, np.int32)
Run Code Online (Sandbox Code Playgroud)
在速度方面.但是,内存视图被认为比numpy数组缓冲区更通用; 你能举一个简单的例子,其中添加的"概括"是重要/有趣的吗?
此外,如果我已经分配了一个指针以使事情尽可能快,那么将它转换为类型化的内存视图有什么好处?(这个问题的答案可能与上面的问题相同)
cdef int *my_arr = <int *> malloc(N * sizeof(int))
cdef int[:] new_arr = <int[:N]>my_arr
Run Code Online (Sandbox Code Playgroud)
Dav*_*idW 21
什么是记忆视图:
当你写一个函数时:
cdef double[:] a
Run Code Online (Sandbox Code Playgroud)
你最终得到一个__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;
Run Code Online (Sandbox Code Playgroud)
memoryview包含一个C指针,它通常不直接拥有一些数据.它还包含一个指向底层Python对象的指针(struct __pyx_memoryview_obj *memview;).如果数据由Python对象拥有,则memview保留对该对象的引用,并确保只要内存视图存在,保存数据的Python对象就会保持活动状态.
指针的原始数据的组合,并且它(如何索引信息shape,strides并suboffsets)允许用Cython做使用原始数据指针和一些简单的C数学(这是非常有效的)的索引.例如:
x=a[0]
Run Code Online (Sandbox Code Playgroud)
给出类似的东西:
(*((double *) ( /* dim=0 */ (__pyx_v_a.data + __pyx_t_2 * __pyx_v_a.strides[0]) )));
Run Code Online (Sandbox Code Playgroud)
相反,如果您使用无类型对象并编写如下内容:
a = np.array([1,2,3]) # note no typedef
x = x[0]
Run Code Online (Sandbox Code Playgroud)
索引完成如下:
__Pyx_GetItemInt(__pyx_v_a, 0, long, 1, __Pyx_PyInt_From_long, 0, 0, 1);
Run Code Online (Sandbox Code Playgroud)
它本身扩展到一大堆Python C-api调用(所以很慢).最终它调用a的__getitem__方法.
与类型化的numpy数组相比:确实没有太大的区别.如果您执行以下操作:
cdef np.ndarray[np.int32_t, ndim=1] new_arr
Run Code Online (Sandbox Code Playgroud)
它实际上非常像一个内存视图,可以访问原始指针,速度应该非常相似.
使用内存视图的优点是可以使用更广泛的数组类型(例如标准库数组),因此您可以更灵活地调用函数类型.这符合Python"鸭子打字"的一般概念 - 你的代码应该使用行为正确的任何参数(而不是检查类型).
第二个(小)优势是你不需要numpy标头来构建你的模块.
第三个(可能更大)的优点是可以在没有GIL的情况下初始化内存视图,而cdef np.ndarrays则不能(http://docs.cython.org/src/userguide/memoryviews.html#comparison-to-the-old-buffer-支持)
内存视图的一个小缺点是它们似乎设置稍慢.
与仅使用malloced int指针相比:
你不会获得任何速度优势(但你也不会得到太多的速度损失).使用memoryview转换的次要优点是:
您可以编写可以在Python中或在Cython内部使用的函数:
cpdef do_something_useful(double[:] x):
# can be called from Python with any array type or from Cython
# with something that's already a memoryview
....
Run Code Online (Sandbox Code Playgroud)你可以让Cython处理这种类型数组的内存释放,这可以简化生命未知事物的生命.见http://docs.cython.org/src/userguide/memoryviews.html#cython-arrays,尤其是.callback_free_data.
您可以将数据传递回python python代码(它将获得底层__pyx_memoryview_obj或类似的东西).在这里要非常小心内存管理(即参见第2点!).
您可以做的另一件事是处理诸如定义为指针指针的2D数组(例如double**).请参阅http://docs.cython.org/src/userguide/memoryviews.html#specifying-more-general-memory-layouts.我通常不喜欢这种类型的数组,但是如果你已经使用了现有的C代码,那么你可以与它接口(并将它传递给Python,这样你的Python代码也可以使用它).
| 归档时间: |
|
| 查看次数: |
4554 次 |
| 最近记录: |