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

Why is Pypy slower for adding numpy arrays?

为了测试 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。难道我做错了什么?还是其他问题?

pypy 不会在所有情况下都对 numpy 数组进行垃圾回收,这可能是您 运行 内存不足、溢出到磁盘然后锁定的原因。

Reducing numpy memory footprint in long-running application

Memory profiler for numpy

有两种解决方法。最简单的方法是简单地告诉 pypy 删除数组:

import gc
del my_array
gc.collect()

这将强制 pypy 进行垃圾回收。请注意,除非确实有必要,否则 gc.collect() 不应置于紧密循环中。

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

这样您仍然可以从 numpy 操作结构,但您可以手动控制 delete/resize 数组。

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

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

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