我需要使用一个C库,它为我提供了一个函数,它将回调函数作为输入。该回调函数依次获取一个数组并返回一个值。例如,
double candidate(double[] x);
将是一个有效的回调。
我想使用Cython实现回调函数,使用Numpy来简化实现。
所以我正在尝试实现一个函数
cdef double cythonCandidate(double[] x):
现在我想立即“转换”x作为numpy数组,然后使用numpy进行操作。
例如,我可能想要写一些类似的东西:
cdef double euclideanNorm(double[] x):
# cast x into a numpy array nx here - dont know how!!
return np.sum(x * x)
Q1。我该怎么做呢?如何在没有显式复制的情况下将C数组转换为numpy数组,而只是引用底层缓冲区?
Q2:使用像我打算的numpy会有python开销吗?
答案 0 :(得分:3)
对于Q1:
%%cython -f
import numpy as np
def test_cast():
cdef double *x = [1, 2, 3, 4, 5]
cdef double[:1] x_view = <double[:5]>x # cast to memoryview, refer to the underlying buffer without copy
xarr = np.asarray(x_view) # numpy array refer to the underlying buffer without copy
x_view[0] = 100
xarr[1] = 200
x[2] = 300
print(xarr.flags) # OWNDATA flag should be False
return x[0],x[1],x[2],x[3],x[4] # (100.0, 200.0, 300.0, 4.0, 5.0)
注意:如果您未声明x_view
并执行此操作xarr = np.asarray(<double[:5]>x)
,则cython编译器可能会崩溃并显示错误消息: AttributeError: 'CythonScope' object has no attribute 'viewscope'
。这可以通过from cython cimport view
修复,例如:
%%cython -f
from cython cimport view # comment this line to see what will happen
import numpy as np
def test_error_cast():
cdef double *x = [1, 2, 3, 4, 5]
xarr = np.asarray(<double[:5]>x)
xarr[0] = 200
return x[0],x[1],x[2],x[3],x[4]
我不知道这是一个功能还是错误。
第二季度: 当数组较小时,numpy开销应该很大。参见下面的基准。
%%cython -a
from cython cimport view
import numpy as np
cdef inline double euclideanNorm(double *x, size_t x_size):
xarr = np.asarray(<double[:x_size]>x)
return np.sum(xarr*xarr)
cdef inline double euclideanNorm_c(double *x, size_t x_size):
cdef double ss = 0.0
cdef size_t i
for i in range(x_size):
ss += x[i] * x[i]
return ss
def c_norm(double[::1] x):
return euclideanNorm_c(&x[0], x.shape[0])
def np_norm(double[::1] x):
return euclideanNorm(&x[0], x.shape[0])
我的电脑中的小阵列:
import numpy as np
small_arr = np.random.rand(100)
print(c_norm(small_arr))
print(np_norm(small_arr))
%timeit c_norm(small_arr) # 1000000 loops, best of 3: 864 ns per loop
%timeit np_norm(small_arr) # 100000 loops, best of 3: 8.51 µs per loop
我的电脑中的大阵列:
big_arr = np.random.rand(1000000)
print(c_norm(big_arr))
print(np_norm(big_arr))
%timeit c_norm(big_arr) # 1000 loops, best of 3: 1.46 ms per loop
%timeit np_norm(big_arr) # 100 loops, best of 3: 4.93 ms per loop