没有numpy临时对象?这是怎么做到的?

时间:2016-03-10 23:13:09

标签: python numpy cython

我在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个。当我用我自己的类替换numpy数组时,我看到它的__mul__函数被调用1,000,000次,导致1,000,000个对象分配。

numpy如何知道它不需要为每次迭代分配临时对象来存储b * i?

1 个答案:

答案 0 :(得分:1)

如果你看一下cython生成的代码,我认为关键行是

__pyx_t_1 = PyNumber_Multiply(__pyx_v_b, __pyx_v_i); // some error checking follows

PyNumber_Multiplythe 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代码,所以我不相信这会产生一个变量,其中之前不存在)。然后我手动编译了文件(在Linux上gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing \ -I/usr/include/python3.4m -o filename.so filename.c)。

打印

  

<class 'numpy.ndarray'>

这确实表明它已经生成了一个普通的numpy数组对象作为临时对象,正如您所料。没有什么魔法可以发生。

作为一个有趣的旁注,我相信Numba的最新版本实际上可以消除临时版本并真正完成整个操作。但是,实际证明这种情况可能会发生,因为您提供的示例稍微超出了我(您可以通过在生成的函数上调用inspect_asm()来看到它,并注意到有很多添加/乘以指令,但不是明显的函数调用。)