为什么numpy.zeros在创建时不分配其所有内存?而我该如何强迫呢?

时间:2018-07-12 20:51:06

标签: python numpy memory

我想在Python中创建一个空的Numpy数组,以便以后用值填充它。下面的代码生成一个具有2个字节整数的1024x1024x1024数组,这意味着它应该在RAM中至少占用2GB。

>>> import numpy as np; from sys import getsizeof
>>> A = np.zeros((1024,1024,1024), dtype=np.int16)
>>> getsizeof(A)
2147483776

getsizeof(A)中,我们看到该数组占用2 ^ 31 + 128字节(可能是标题信息)。但是,使用任务管理器,我可以看到 Python仅占用18.7 MiB的内存

假定数组已压缩,我为每个内存插槽分配了随机值,以使它不能被压缩。

>>> for i in range(1024):
...   for j in range(1024):
...     for k in range(1024):
...         A[i,j,k] = np.random.randint(32767, dtype = np.int16)

循环仍在运行,并且我的RAM正在缓慢增加(大概是因为数组组成A膨胀并带有难以理解的噪声。)我假设这样做会使我的代码更快,迫使numpy从一开始就扩展此数组。奇怪的是,我还没有在任何地方看到此文件!

因此,1.为什么numpy这样做?和2.如何强制numpy分配内存?

1 个答案:

答案 0 :(得分:0)

让我们看一下较小情况下的一些时间安排:

In [107]: A = np.zeros(10000,int)
In [108]: for i in range(A.shape[0]): A[i]=np.random.randint(327676)

我们无需制作A 3d即可获得相同的效果;总尺寸相同的1d就好。

In [109]: timeit for i in range(A.shape[0]): A[i]=np.random.randint(327676)
37 ms ± 133 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

现在将这段时间与一次调用生成随机数的方法进行比较:

In [110]: timeit np.random.randint(327676, size=A.shape)
185 µs ± 905 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

快得多。

如果我们执行相同的循环,但只需将随机数分配给变量(并将其丢弃):

In [111]: timeit for i in range(A.shape[0]): x=np.random.randint(327676)
32.3 ms ± 171 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

时间几乎与原始情况相同。将值分配给zeros数组并不是大的时间消耗。

我没有像您一样测试很大的情况,并且我的A已经被完全初始化。因此,欢迎您重复比较您的尺寸。但是我认为该模式仍然适用-迭代1024x1024x1024次(比我的示例大10万次)是大量的时间消耗,而不是内存分配任务。

您可能会尝试的其他方法:仅对A的第一个维度进行迭代,然后分配形状类似于其他两个维度的randomint。例如,将我的A的尺寸扩展为10:

In [112]: A = np.zeros((10,10000),int)
In [113]: timeit for i in range(A.shape[0]): A[i]=np.random.randint(327676,size=A.shape[1])
1.95 ms ± 31.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

A比[107]中的大10倍,但填充时间却减少了16倍,因为它只会迭代10倍。在numpy中,如果必须进行迭代,请尝试对更复杂的任务进行几次。

({timeit重复测试多次(例如7 * 10),因此即使我使用足够大的数组,它也不会捕获任何初始内存分配步骤)。 / p>