3

我想使用类型化的内存视图来优化函数,但我不知道参数类型是什么。它可以是一个 numpy 数组,甚至是一个标量。那我应该如何使用类型化的 memoryview 呢?

4

1 回答 1

2

这类问题的问题在于 Python 是动态类型的,因此在选择要采用的代码路径时总是会失去速度。但是,原则上您可以使各个代码路径非常快。一种可能会给您带来良好结果的方法是:

  1. 定义一个在 1D memoryview 上运行的“实现”函数。
  2. 定义一个对任何 python 对象进行操作的包装函数。
    1. 如果传递的是一维内存视图,则调用实现函数;
    2. 如果它传递了一个标量,则创建一个 1x1 数组并调用实现函数;
    3. 如果它传递了一个多维数组,那么要么将其展平以用于实现函数,要么迭代行,为每一行调用实现函数。

下面是一个快速的实现。这假设您希望将一个函数应用于输入数组的每个元素(并希望输出数组的大小相同)。我选择的说明性函数只是将每个值加 1。它还在我认为合理的地方(而不仅仅是键入的内存视图)使用 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,它提供了一个接口来有效地实现这种事情。(见http://docs.scipy.org/doc/numpy-dev/user/c-info.ufunc-tutorial.html)。不幸的是,它们比 Cython 更复杂。

于 2015-05-05T13:49:12.147 回答