在Python中生成非常大的二维数组?

2 投票
1 回答
3934 浏览
提问于 2025-04-18 11:20

我想用列表的列表来生成一个非常大的二维数组(也就是一个矩阵)。每个元素应该是一个浮点数。

举个例子,假设我们有以下代码:

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的内存,但是当代码运行到矩阵的第10000行时,我的内存已经满了。现在,如果我没记错的话,每个浮点数占用64位(也就是8字节),所以总共占用的内存应该是:

32000 * 32000 * 8 / 1 MB = 8192 MB

为什么Python会占满我的整个内存,甚至开始使用交换空间?

1 个回答

3

Python中的列表并不一定会以最紧凑的方式存储每个元素,因为列表需要指向下一个元素的指针等等。这是因为列表这种数据类型允许我们进行删除、插入等操作的副作用。以一个简单的双向链表为例,它需要两个指针加上一个值,在64位的机器上,每个浮点数在列表中大约占用24个字节。实际上,Python的实现并没有那么笨,但仍然会有一些额外的开销。

如果你想要更紧凑的格式,我建议使用 numpy.array,因为它的内存使用量会正好是你预期的那样(加上一点小开销)。

编辑 哎呀,刚才说的不一定对。解释错了,但建议是对的。numpy确实是合适的工具,因为numpy.array就是为了这个目的而存在的。不过,问题可能是别的原因。我的电脑虽然需要很长时间(大约2分钟)来运行这个过程,但还是能运行。而且,退出Python后也需要很长时间(实际上是卡住了)。根据top的报告,Python进程的内存使用量最高达到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

(字节计数并不是完全可靠,因为对象本身也需要一些空间来存储元数据等等。必须有指向内存块起始位置的指针、数据类型、数组形状等信息。)

这花费的时间要少得多。创建数组几乎是瞬间完成的,插入数字可能只需要一两秒。分配和释放很多小内存块是耗时的,虽然在64位机器上不会造成碎片问题,但分配一大块数据要简单得多。

如果你有很多数据可以放进数组里,你需要有充分的理由不使用numpy

撰写回答