cython - 如果尺寸未知,请在 cython 中使用 Typed memoryview

标签 cython memoryview

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

最佳答案

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

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

接下来是快速实现。这假设您想要一个函数应用于输入数组的每个元素(并且想要一个相同大小的输出数组)。我选择的说明性函数只是将每个值加 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/

相关文章:

android - Android Studio 有 NDK 内存查看器吗?

python - Cython:将单个元素分配给多维内存 View 切片

python - 如何向 PySCIPOpt 类添加属性

python - 一种将 C++ 对象传递给 cython 中另一个对象的方法的方法

python - cython 中的关键部分

python - 使用内存 View 读取二进制文件

python - 在 bytes 对象上获取指向 python memoryview 的指针

python - 快速迭代多维 numpy 数组中的向量

python - Cython:如何将 C 函数分配给 Python/Cython 变量?

python - Cython Memoryview 作为返回值