Python列表/字典与numpy数组:性能与内存控制

时间:2011-02-08 16:56:17

标签: python performance memory-management

我必须迭代地读取数据文件并将数据存储到(numpy)数组中。我选择将数据存储到“数据字段”字典中:{'field1':array1,'field2':array2,...}。

案例1(清单):

使用列表(或 collections.deque())来“追加”新数据阵列,代码高效。但是,当我连接存储在列表中的数组时,内存增长,我无法再次释放它。例如:

filename = 'test'
# data file with a matrix of shape (98, 56)
nFields = 56
# Initialize data dictionary and list of fields
dataDict = {}

# data directory: each entry contains a list 
field_names = []
for i in xrange(nFields):
    field_names.append(repr(i))
    dataDict[repr(i)] = []

# Read a data file N times (it represents N files reading)
# file contains 56 fields of arbitrary length in the example
# Append each time the data fields to the lists (in the data dictionary)
N = 10000
for j in xrange(N):
    xy = np.loadtxt(filename)
    for i,field in enumerate(field_names):
        dataDict[field].append(xy[:,i])

# concatenate list members (arrays) to a numpy array 
for key,value in dataDict.iteritems():
    dataDict[key] = np.concatenate(value,axis=0)

计算时间 63.4 s
内存使用情况(上):13862 gime_se 20 0 1042m 934m 4148 S 0 5.8 1:00.44 python

案例2(numpy数组):

每次加入时,

直接连接 numpy数组效率低内存仍然受控制 。例如:

nFields = 56
dataDict = {}
# data directory: each entry contains a list 
field_names = []
for i in xrange(nFields):
    field_names.append(repr(i))
    dataDict[repr(i)] = np.array([])

# Read a data file N times (it represents N files reading)
# Concatenate data fields to numpy arrays (in the data dictionary)
N = 10000
for j in xrange(N):
    xy = np.loadtxt(filename)
    for i,field in enumerate(field_names):
        dataDict[field] = np.concatenate((dataDict[field],xy[:,i])) 

计算时间 1377.8 s
内存使用情况(上):14850 gime_se 20 0 650m 542m 4144 S 0 3.4 22:31.21 python

问题(S):

  • 有没有办法表现案例1 ,但保持内存受控,如案例2

  • 似乎在情况1中,当连接列表成员(np.concatenate(value,axis = 0))时内存增长。更好的想法呢?

1 个答案:

答案 0 :(得分:2)

根据我观察到的情况,这是正在发生的事情。没有真正的内存泄漏。相反,Python的内存管理代码(可能与你所在的操作系统的内存管理有关)决定保留程序中原始字典(没有连接数组的字典)使用的空间。但是,它可以自由重复使用。我通过以下方式证明了这一点:

  1. 将您提供的代码作为回复dataDict的函数的答案。
  2. 调用该函数两次并将结果分配给两个不同的变量。
  3. 当我这样做时,我发现使用的内存量仅从~900 GB增加到~1.3 GB。如果没有额外的字典内存,Numpy数据本身应该占用我的计算大约427 MB,所以这个加起来。我们的函数创建的第二个初始的,非复杂的字典只使用了已经分配的内存。

    如果你真的不能使用超过600 MB的内存,那么我建议你使用你的Numpy数组,就像在Python内部做的那样:分配一个包含一定数量列的数组,当你'使用它们,创建一个包含更多列的放大数组并复制数据。这将减少连接数,这意味着它会更快(尽管仍然没有列表那么快),同时保持内存使用率下降。当然,实施起来也更加痛苦。