我想使用类型化的内存 View 来优化函数,但我不知道参数类型是什么。它可以是一个 numpy 数组,甚至是一个标量。那我应该如何使用类型化的内存 View 呢?
最佳答案
这类问题的问题在于 Python 是动态类型的,因此在选择要采用的代码路径时,您总是会失去速度。但是,原则上您可以使各个代码路径非常快。一种可能会给您带来好的结果的方法是:
- 定义一个在 1D 内存 View 上运行的“实现”函数。
- 定义一个可对任何 python 对象进行操作的包装函数。
- 如果传入一维内存 View ,则调用实现函数;
- 如果传递的是标量,则创建一个 1x1 数组并调用实现函数;
- 如果它传递了一个多维数组,则要么将其展平以用于实现函数,要么遍历行,为每一行调用实现函数。
接下来是快速实现。这假设您想要一个函数应用于输入数组的每个元素(并且想要一个相同大小的输出数组)。我选择的说明性函数只是将每个值加 1。它还在我认为合理的地方(而不仅仅是类型化的内存 View )使用了 numpy:
cimport cython
import numpy as np
import numbers
@cython.boundscheck(False)
cdef double[:] _plus_one_impl(double[:] x):
cdef int n
cdef double[:] output
output = x.copy()
for n in range(x.shape[0]):
output[n] = x[n]+1
return output
def plus_one(x):
if isinstance(x,numbers.Real): # check if it's a number
return _plus_one_impl(np.array([x]))[0]
else:
try:
return _plus_one_impl(x)
except ValueError: # this gets thrown if conversion fails
if len(x.shape)<2:
raise ValueError('x could not be converted to double [:]')
output = np.empty_like(x) # output is all numpy, whatever the input is
for n in range(x.shape[0]): # this loop isn't typed, so is likely to be pretty slow
output[n,...] = plus_one(x[n,...])
return output
在某些情况下,此代码可能会变得有些慢(即具有较短第二维的二维数组)。
但是,我真正的建议是研究 numpy ufuncs,它提供了一个接口(interface)来有效地实现这种事情。 (参见 http://docs.scipy.org/doc/numpy-dev/user/c-info.ufunc-tutorial.html)。不幸的是,它们比 Cython 更复杂。
关于cython - 如果尺寸未知,请在 cython 中使用 Typed memoryview,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29484943/