我想使用列表列表生成非常大的2D数组(或者,换句话说,矩阵)。每个元素都应该是一个浮点数。
所以,举一个例子,让我们假设有以下代码:
import numpy as np
N = 32000
def largeMat():
m = []
for i in range(N):
l = list(np.ones(N))
m.append(l)
if i % 1000 == 0:
print i
return m
m = largeMat()
我有12GB的RAM,但是当代码到达矩阵的第10000行时,我的RAM已经满了。现在,如果我没错,每个浮点数都是64位大(或8字节),因此占用的总RAM应为:
32000 * 32000 * 8 / 1 MB = 8192 MB
为什么python会填满我的整个RAM,甚至开始分配到swap?
答案 0 :(得分:3)
Python不一定以最紧凑的形式存储列表项,因为列表需要指向下一项的指针等。这是一种允许删除,插入等数据类型的副作用。对于简单的两个 - 方式链表列表的用法是两个指针加上值,在64位机器中,列表中每个浮点项目为24个八位字节。在实践中,实现并不是那么愚蠢,但仍然存在一些开销。
如果您想要一个简洁的格式,我建议使用numpy.array
,因为它会花费您认为它所需的字节数(加上一小部分开销)。
修改糟糕。不必要。解释错误,建议有效。由于这个原因,numpy
是numpy.array
存在的正确工具。但是,问题很可能是其他问题。即使需要花费很多时间(大约2分钟),我的计算机也会运行该程序。此外,在此之后退出python需要很长时间(实际上,它挂起)。内存使用python进程(由top
报告)在10 000 MB处达到峰值,然后降至略低于9 000 MB。分配的numpy
数组可能不会非常快速地进行垃圾回收。
但关于我机器中的原始数据大小:
>>> import sys
>>> l = [0.0] * 1000000
>>> sys.getsizeof(l)
8000072
因此,每个列表似乎有72个八位字节的固定开销。
>>> listoflists = [ [1.0*i] * 1000000 for i in range(1000)]
>>> sys.getsizeof(listoflists)
9032
>>> sum([sys.getsizeof(l) for l in listoflists])
8000072000
所以,这是预期的。
另一方面,保留和填写长列表需要一段时间(大约10秒)。另外,退出python需要一段时间。 numpy也一样:
>>> a = numpy.empty((1000,1000000))
>>> a[:] = 1.0
>>> a.nbytes
8000000000
(字节数不完全可靠,因为对象本身需要一些空间用于元数据等。必须有指向内存块开头,数据类型,数组形状等的指针)。 p>
这花费的时间少得多。阵列的创建几乎是即时的,插入数字可能需要一两秒钟。分配和释放大量小内存块非常耗时,虽然它不会在64位计算机中造成碎片问题,但分配大量数据仍然要容易得多。
如果您有大量可以放入数组的数据,则需要一个不使用numpy
的充分理由。