如何将Numpy数组传递给cffi函数以及如何将其返回?

bas*_*ibe 26 python arrays numpy python-cffi

我正在使用Python和Numpy开发音频算法.现在我想通过在C中实现它的一部分来加速该算法.在过去,我使用cython完成了这个.现在我想用新的cffi做同样的事情.

出于测试目的,我写了一个简单的C函数:

void copy(float *in, float *out, int len) {
    for (int i=0; i<len; i++) {
        out[i] = in[i];
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想创建两个numpy数组,并由这个函数处理.我想出了一种方法:

import numpy as np
from cffi import FFI

ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("/path/to/copy.dll")

float_in = ffi.new("float[16]")
float_out = ffi.new("float[16]")

arr_in = 42*np.ones(16, dtype=np.float32)

float_in[0:16] = arr_in[0:16]
C.copy(float_in, float_out, 16)
arr_out = np.frombuffer(ffi.buffer(float_out, 16*4), dtype=np.float32)
Run Code Online (Sandbox Code Playgroud)

但是,我想改进这段代码:

  1. 有没有办法直接访问numpy数组的底层浮点缓冲区而不复制它们?
  2. ffi.buffer非常方便快速转换为C数组的内容到Numpy数组.是否有一种等效方法可以快速将numpy数组转换为C数组而无需复制单个元素?
  3. 对于某些应用程序,float_in[0:16] = arr_in[0:16]是一种访问数据的便捷方式.相反,arr_out[0:16] = float_out[0:16]不起作用.为什么不?

HYR*_*YRY 22

ctypesndarray 的属性可以与ctypes模块交互,例如,ndarray.ctypes.data是数组的数据地址,可以将其转换为float *指针,然后将指针传递给C函数.

import numpy as np
from cffi import FFI

ffi = FFI()
ffi.cdef("void copy(float *in, float *out, int len);")
C = ffi.dlopen("ccode.dll")

a = 42*np.ones(16, dtype=np.float32)
b = np.zeros_like(a)
pa = ffi.cast("float *", a.ctypes.data)
pb = ffi.cast("float *", b.ctypes.data)

C.copy(pa, pb, len(a))
print b
Run Code Online (Sandbox Code Playgroud)

对于你的问题3:

我认为ffi数组不会为访问它的内部缓冲区提供必要的信息.所以numpy尝试将其转换为失败的浮点数.

我能想到的最好的解决方案是首先将其转换为列表:

float_in[0:16] = list(arr_in[0:16])
Run Code Online (Sandbox Code Playgroud)


小智 13

numpy数组中的数据可以通过它的数组接口访问:

import numpy as np
import cffi
ffi = cffi.FFI()

a = np.zeros(42)
data = a.__array_interface__['data'][0]
cptr = ffi.cast ( "double*" , data )
Run Code Online (Sandbox Code Playgroud)

现在您有一个cffi指针类型,您可以将其传递给复制例程.请注意,这是一种基本方法; numpy数组可能不包含它们在平面内存中的数据,所以如果你的ndarray是结构化的,你将不得不考虑它的形状和步幅.但是,如果它完全平坦,这就足够了.


Arm*_*igo 10

对此的更新:现代版本的CFFI具有ffi.from_buffer(),它将任何缓冲区对象(如numpy数组)转换为char *FFI指针.你现在可以直接做:

cptr = ffi.cast("float *", ffi.from_buffer(my_np_array))
Run Code Online (Sandbox Code Playgroud)

或直接作为调用的参数(char *自动转换为float *):

C.copy(ffi.from_buffer(arr_in), ffi.from_buffer(arr_out), 16)
Run Code Online (Sandbox Code Playgroud)