没有 numpy 临时对象?这是怎么做到的?
No numpy temporary objects? How is this done?
我是 运行 Cython 函数中的以下代码:
a = np.zeros((3,3,))
b = np.ones((3,3,))
for i in range(1000000):
a += b * i
return a
在此代码中,只有两个 numpy 数组分配。我希望其中有 1,000,002 个。当我用自己的 class 替换 numpy 数组时,我看到它的 __mul__
函数被调用了 1,000,000 次,导致 1,000,000 次对象分配。
numpy 怎么知道它不需要为每次迭代分配临时对象来存储 b * i?
如果你看一下 cython 生成的代码,我认为关键行是
__pyx_t_1 = PyNumber_Multiply(__pyx_v_b, __pyx_v_i); // some error checking follows
PyNumber_Multiply
是 the standard c-api function to call the multiplication operator 所以没有理由相信它的行为方式与普通的乘法调用不同。但是,我们可以很容易地检查中间体的类型……我拿了编译后的 C 文件并插入了行
if (__Pyx_PrintOne(0, ((PyObject *)Py_TYPE(__pyx_t_1))) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
(这个只是看print(type(a))
生成的代码,改了一个变量名得到的,注意我没有改Python的代码,所以我不信这会生成一个以前不存在的变量)。然后我手动编译了文件(gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing \ -I/usr/include/python3.4m -o filename.so filename.c
on linux)。
这会打印
<class 'numpy.ndarray'>
这确实表明它已经生成了一个普通的 numpy 数组对象作为临时对象,正如您所期望的那样。没有魔法发生。
作为一个有趣的旁注,我相信 Numba 的最新版本实际上可以消除临时性并真正地完成整个操作。然而,实际上证明你给出的例子会发生这种情况有点超出我的范围(你可以通过在生成的函数上调用 inspect_asm()
来看到它,并注意到有很多 add/multiply 指令,但不是明显的函数调用)。
我是 运行 Cython 函数中的以下代码:
a = np.zeros((3,3,))
b = np.ones((3,3,))
for i in range(1000000):
a += b * i
return a
在此代码中,只有两个 numpy 数组分配。我希望其中有 1,000,002 个。当我用自己的 class 替换 numpy 数组时,我看到它的 __mul__
函数被调用了 1,000,000 次,导致 1,000,000 次对象分配。
numpy 怎么知道它不需要为每次迭代分配临时对象来存储 b * i?
如果你看一下 cython 生成的代码,我认为关键行是
__pyx_t_1 = PyNumber_Multiply(__pyx_v_b, __pyx_v_i); // some error checking follows
PyNumber_Multiply
是 the standard c-api function to call the multiplication operator 所以没有理由相信它的行为方式与普通的乘法调用不同。但是,我们可以很容易地检查中间体的类型……我拿了编译后的 C 文件并插入了行
if (__Pyx_PrintOne(0, ((PyObject *)Py_TYPE(__pyx_t_1))) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 11; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
(这个只是看print(type(a))
生成的代码,改了一个变量名得到的,注意我没有改Python的代码,所以我不信这会生成一个以前不存在的变量)。然后我手动编译了文件(gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing \ -I/usr/include/python3.4m -o filename.so filename.c
on linux)。
这会打印
<class 'numpy.ndarray'>
这确实表明它已经生成了一个普通的 numpy 数组对象作为临时对象,正如您所期望的那样。没有魔法发生。
作为一个有趣的旁注,我相信 Numba 的最新版本实际上可以消除临时性并真正地完成整个操作。然而,实际上证明你给出的例子会发生这种情况有点超出我的范围(你可以通过在生成的函数上调用 inspect_asm()
来看到它,并注意到有很多 add/multiply 指令,但不是明显的函数调用)。