Python Cython:键入内存视图是键入numpy数组的现代方式吗?

Python Cython:键入内存视图是键入numpy数组的现代方式吗?,python,numpy,cython,Python,Numpy,Cython,假设我想将numpy数组传递给cdef函数: cdef double mysum(double[:] arr): cdef int n = len(arr) cdef double result = 0 for i in range(n): result = result + arr[i] return result 这是处理键入numpy数组的现代方法吗?与这个问题相比: 如果我要执行以下操作,该怎么办: cdef double[:] my

假设我想将numpy数组传递给
cdef
函数:

cdef double mysum(double[:] arr):
    cdef int n = len(arr)
    cdef double result = 0

    for i in range(n):
        result = result + arr[i]

    return result
这是处理键入numpy数组的现代方法吗?与这个问题相比:

如果我要执行以下操作,该怎么办:

cdef double[:] mydifference(int a, int b):
    cdef double[:] arr_a = np.arange(a)
    cdef double[:] arr_b = np.arange(b)

    return arr_a - arr_b
这将返回一个错误,因为没有为MemoryView定义
-
。那么,该案件是否应按以下方式处理

cdef double[:] mydifference(int a, int b):
    arr_a = np.arange(a)
    arr_b = np.arange(b)

    return arr_a - arr_b

我将引用文件中的内容

MemoryView类似于当前的NumPy数组缓冲区支持(
np.ndarray[np.float64\u t,ndim=2]
),但它们有更多的功能和更清晰的语法

这表明Cython的开发人员认为内存视图是现代的方式。 内存视图与

np.ndarray
表示法相比,主要在优雅性和互操作性方面提供了一些巨大的优势,但是它们的性能并不优越

性能: 首先需要注意的是,boundscheck有时无法处理内存视图,从而导致boundscheck=True的MemoryView的人为快速图形(即,您得到的是快速、不安全的索引),如果您依赖boundscheck来捕获bug,这可能是一个令人讨厌的惊喜

在大多数情况下,一旦应用了编译器优化,内存视图和numpy数组表示法在性能上是相等的,通常恰恰如此。当存在差异时,通常不超过10-30%

绩效基准 该数字是以秒为单位执行100000000次操作的时间。越小越快

ACCESS+小数组赋值(10000个元素,10000次)
‘uint8’的结果`
1) 内存视图:0.0415+/-0.0017
2) np.ndarray:0.0531+/-0.0012
3) 指针:0.0333+/-0.0017
‘uint16’的结果`
1) 内存视图:0.0479+/-0.0032
2) np.ndarray:0.0480+/-0.0034
3) 指针:0.0329+/-0.0008
‘uint32’的结果`
1) 内存视图:0.0499+/-0.0021
2) np.ndarray:0.0413+/-0.0005
3) 指针:0.0332+/-0.0010
‘uint64’的结果`
1) 内存视图:0.0489+/-0.0019
2) np.ndarray:0.0417+/-0.0010
3) 指针:0.0353+/-0.0017
第32段的结果`
1) 内存视图:0.0398+/-0.0027
2) np.ndarray:0.0418+/-0.0019
3) 指针:0.0330+/-0.0006
第64段的结果`
1) 内存视图:0.0439+/-0.0037
2) np.ndarray:0.0422+/-0.0013
3) 指针:0.0353+/-0.0013
访问性能(100000000个元素阵列):
‘uint8’的结果`
1) 内存视图:0.0576+/-0.0006
2) np.ndarray:0.0570+/-0.0009
3) 指针:0.0061+/-0.0004
‘uint16’的结果`
1) 内存视图:0.0806+/-0.0002
2) np.ndarray:0.0882+/-0.0005
3) 指针:0.0121+/-0.0003
‘uint32’的结果`
1) 内存视图:0.0572+/-0.0016
2) np.ndarray:0.0571+/-0.0021
3) 指针:0.0248+/-0.0008
‘uint64’的结果`
1) 内存视图:0.0618+/-0.0007
2) np.ndarray:0.0621+/-0.0014
3) 指针:0.0481+/-0.0006
第32段的结果`
1) 内存视图:0.0945+/-0.0013
2) np.ndarray:0.0947+/-0.0018
3) 指针:0.0942+/-0.0020
第64段的结果`
1) 内存视图:0.0981+/-0.0026
2) np.ndarray:0.0982+/-0.0026
3) 指针:0.0968+/-0.0016
分配性能(100000000个元素数组):
‘uint8’的结果`
1) 内存视图:0.0341+/-0.0010
2) np.ndarray:0.0476+/-0.0007
3) 指针:0.0402+/-0.0001
‘uint16’的结果`
1) 内存视图:0.0368+/-0.0020
2) np.ndarray:0.0368+/-0.0019
3) 指针:0.0279+/-0.0009
‘uint32’的结果`
1) 内存视图:0.0429+/-0.0022
2) np.ndarray:0.0427+/-0.0005
3) 指针:0.0418+/-0.0007
‘uint64’的结果`
1) 内存视图:0.0833+/-0.0004
2) np.ndarray:0.0835+/-0.0011
3) 指针:0.0832+/-0.0003
第32段的结果`
1) 内存视图:0.0648+/-0.0061
2) np.ndarray:0.0644+/-0.0044
3) 指针:0.0639+/-0.0005
第64段的结果`
1) 内存视图:0.0854+/-0.0056
2) np.ndarray:0.0849+/-0.0043
3) 指针:0.0847+/-0.0056
基准代码(仅针对访问+分配显示)
#cython:boundscheck=False
#cython:wrapparound=False
#cython:nonecheck=False
将numpy作为np导入
cimport numpy作为np
西姆波特赛顿酒店
#根据需要更改这些。
数据类型=np.uint64
ctypedef np.uint64数据类型
cpdef测试内存视图(数据类型[:]视图):
cdef Py_ssize_t i,j,n=view.shape[0]
对于范围(0,n)内的j:
对于范围(0,n)内的i:
视图[i]=视图[j]
cpdef测试阵列(np.ndarray[数据类型,ndim=1]视图):
cdef Py_ssize_t i,j,n=view.shape[0]
对于范围(0,n)内的j:
对于范围(0,n)内的i:
视图[i]=视图[j]
cpdef测试指针(数据类型[:]视图):
cdef Py_ssize_t i,j,n=view.shape[0]
cdef数据类型*数据类型=&视图[0]
对于范围(0,n)内的j:
对于范围(0,n)内的i:
(数据_ptr+i)[0]=(数据_ptr+j)[0]
def run_测试():
导入时间
从统计数据导入stdev,表示
n=10000
重复次数=100
a=np.arange(0,n,数据类型=数据类型)
funcs=[('1)内存视图',测试内存视图),
('2)np.ndarray',testndarray),
('3)指针',测试指针)]
结果={label:[]对于label,func in funcs}
对于范围内的r(0,重复):
对于标签,函数中的函数:
开始=时间。时间()
func(a)
结果[标签].append(time.time()-start)
打印(“{}”的结果。格式(数据类型、名称)
对于标签,已排序的时间(results.items()):

print(“{:Cython支持numpy类型,请参阅。顺便说一句,我没有看到您使用
double[:]链接问题的答案
,它是按照文档建议的方式来做的。@simonzack是的,我想展示一个例子,说明文档是如何做的。相关:我还应该注意,如果你真的关心速度,手动指针算法可以比
np.ndarray快1.1x-3x,尽管这在很大程度上取决于类型和操作。不是吗推荐这篇文章,只是为了透视而提一下;)。嗨,班特——非常感谢!和往常一样,回答得很好。我
cdef double [:, :] data_view = <double[:256, :256]>data
def dostuff(arr):
    cdef double [:] arr_view = arr
    # Now you can use 'arr' if you want array functions,
    # and arr_view if you want fast indexing