为什么Pypy添加numpy数组的速度较慢?

时间:2017-03-01 15:55:41

标签: python arrays numpy pypy

为了测试Pypy JIT明显更快的说法,我写了一个简单的代码,重复添加两个大小为1200x1200的数组。我的代码如下

import numpy as np
import random

a=np.zeros((1200, 1200), dtype=np.float32)
b=np.zeros((1200, 1200), dtype=np.float32)
import timeit
#Start timer
start=timeit.default_timer()
#Initialize the arrays
for j in range(1200):
    for k in range(1200):
        a[j][k]=random.random()
        b[j][k]=random.random()
#Repeatedly add the arrays    
for j in range(10):
    a=np.add(a,b)
#Stop timer and display the results
stop=timeit.default_timer()
print stop-start

使用普通的python执行时间约为1.2 - 1.5秒。然而对于Pypy它超过15秒? 同样在上面的例子中,我只添加了10次数组。如果我将此值增加到1000,我的计算机将停止响应。我发现这是因为在使用pypy时几乎消耗了整个RAM。难道我做错了什么?或者是其他问题?

2 个答案:

答案 0 :(得分:1)

在任何情况下,pypy都不会在numpy数组中进行垃圾收集,这可能是你内存耗尽,溢出到磁盘然后锁定的原因。

numpy.ndarray objects not garbage collected

Reducing numpy memory footprint in long-running application

Memory profiler for numpy

有两种解决方案。最简单的方法是通过执行以下操作告诉pypy删除数组:

import gc
del my_array
gc.collect()

这将迫使pypy进行垃圾收集。请注意,gc.collect()不应该被置于紧密的循环中,除非它确实非常必要。

第二个更手动的解决方案是使用CFFI自己创建数组,并使用数组接口告诉他们:https://docs.scipy.org/doc/numpy/reference/arrays.interface.html

这样你仍然可以从numpy操作struct,但你可以手动删除/调整数组大小。

答案 1 :(得分:0)

在这种情况下,JIT无法提供帮助,因为在python代码中花费的时间非常少。 NumPy是用C语言编写的,因此JIT无法查看该代码并使其更快。事实上,PyPy在这种情况下受到影响,因为用RPython编写的PyPy和用C编写的NumPy之间的阻抗匹配意味着每次从PyPy调用NumPy函数时,必须运行额外的转换代码来准备和调用C函数。

CFFI专门针对此用例编写,调用C所需的转换已在对象创建时处理,因此程序可以更加无缝地运行。

内存问题是一个单独的问题,应该修复,请参阅上面的垃圾收集问题的答案。