正如在这个SO-post中指出的,vectorize
wrapsfrompyfunc
并正确处理返回数组的类型,而frompyfunc
返回一个np.object
的数组。你知道吗
然而,对于所有规模而言,frompyfunc
始终优于vectorize
10-20%,这也不能用不同的回报类型来解释。你知道吗
考虑以下变体:
import numpy as np
def do_double(x):
return 2.0*x
vectorize = np.vectorize(do_double)
frompyfunc = np.frompyfunc(do_double, 1, 1)
def wrapped_frompyfunc(arr):
return frompyfunc(arr).astype(np.float64)
wrapped_frompyfunc
只是将frompyfunc
的结果转换为正确的类型—正如我们所见,此操作的成本几乎可以忽略不计。你知道吗
它导致以下计时(蓝线是frompyfunc
):
我希望vectorize
会有更多的开销,但这应该只适用于小尺寸。另一方面,将np.object
转换成np.float64
也是在wrapped_frompyfunc
中完成的,这要快得多。你知道吗
如何解释这种性能差异?你知道吗
使用perfplot包生成定时比较的代码(给定上述函数):
import numpy as np
import perfplot
perfplot.show(
setup=lambda n: np.linspace(0, 1, n),
n_range=[2**k for k in range(20,27)],
kernels=[
frompyfunc,
vectorize,
wrapped_frompyfunc,
],
labels=["frompyfunc", "vectorize", "wrapped_frompyfunc"],
logx=True,
logy=False,
xlabel='len(x)',
equality_check = None,
)
注意:对于较小的大小,vectorize
的开销要高得多,但这是意料之中的(毕竟它包装了frompyfunc
):
按照@hpaulj的提示,我们可以分析
vectorize
-函数:这表明100%的时间都花在
_vectorize_call
:它显示了我在假设中遗漏的部分:双数组完全在预处理步骤中转换为对象数组(在内存方面这样做不是很明智)。其他部分与
wrapped_frompyfunc
类似:当我们查看峰值内存消耗(例如,通过} (8192)的块中处理,因此此时内存中只存在8192个python浮点(24字节+8字节指针)相同的时间(而不是数组中的元素数,这可能要高得多)。从操作系统中保留内存的成本+更多的缓存未命中可能会导致更高的运行时间。你知道吗
/usr/bin/time python script.py
)时,我们将看到vectorized
版本的内存消耗是frompyfunc
的两倍,后者使用了更复杂的策略:双数组在大小为^{我的收获:
frompyfunc
有一种更复杂的方法来处理这些转换。你知道吗ufunc
应该用在“实代码”中时,也不应该使用vectorize
或frompyfunc
。相反,应该用C或者使用numba/类似的语言来编写它。你知道吗在对象数组上调用
frompyfunc
比在双数组上调用frompyfunc
所需的时间更少:但是,上面的测线探查器计时没有显示出在对象上使用
ufunc
而不是双倍的优势:3.089595s对3014961.0s。我怀疑这是因为在创建所有对象的情况下缓存未命中更多,而在二级缓存中只有8192个创建的对象(256Kb)是热的。你知道吗相关问题 更多 >
编程相关推荐