【发布时间】:2021-03-18 11:17:23
【问题描述】:
我有一个有点做作的例子来进行 cytonize,我想要一个函数来:
- 接受任意长度的一维
numpy数组(~100'000 ÷ 1'000'000np.float64's) - 对其进行一些过滤
- 以相同长度的新 [numpy?] 数组形式返回结果
代码和分析如下:
%%cython -a
from libc.stdlib cimport malloc, free
from cython cimport boundscheck, wraparound
import numpy as np
@boundscheck(False)
@wraparound(False)
def func_memview(double[:] arr):
cdef:
int N = arr.shape[0], i
double *out_ptr = <double *> malloc(N * sizeof(double))
double[:] out = <double[:N]>out_ptr
for i in range(1, N):
if arr[i] > arr[i-1]:
out[i] = arr[i]
else:
out[i] = 0.
free(out_ptr)
return np.asarray(out)
我的问题是我能做得更好吗?
【问题讨论】:
-
free(out_ptr); return np.asarray(out)绝对可以做得更好!就我个人而言,我只会在函数的开头使用np.empty((N,)),并避免使用malloc。 -
@DavidW 在顶部做
out = np.empty(N,)让我的时间差了 15 倍...可以作为答案的一个例子吗? -
您当前代码的问题在于
out是out_ptr的内存视图。如果你删除out_ptr,那么你也不能使用out。在短期内你可能会侥幸逃脱,但最终记忆会被覆盖。我认为(但我不是 100% 确定)np.asarray(out)没有制作另一个副本,但始终是相同(无效)内存的另一个视图。out = np.empty(N,)可能会更慢,但它确实有效!我现在没有一个简单的方法来测试一个完整的答案,但是如果没有其他人先给出一个,我稍后会写一个。 -
@DavidW 如果你能展示一些可以改进时间的代码,我真的很感激。
-
还有一个小问题,如果你坚持使用c指针版本,你需要检查malloc的结果以确保它不为NULL,如果内存分配失败就会发生这种情况(例如,您的 RAM 碎片化或没有足够的空间来分配数组)。