文件数据到阵列使用了大量内存

时间:2016-07-02 20:57:29

标签: python memory memory-management

我正在使用带有制表符分隔值的大型文本文件并将它们添加到数组中。

当我在一个32 Mb的文件上运行我的代码时,python内存消耗量会上升;使用大约500 Mb RAM。

我需要能够为2 GB文件运行此代码,甚至可能运行更大的文件。

我目前的代码是:

markers = []

def parseZeroIndex():
    with open('chromosomedata') as zeroIndexes:
        for line in zeroIndexes:
            markers.append(line.split('\t'))

parseZeroIndex()

不能按原样对我的2 GB文件运行此代码。文件如下所示:

per1    1029292 string1 euqye
per1    1029292 string2 euqys

我的问题是:

什么是使用所有这些记忆?

什么是更有效的方式来做这个记忆?

1 个答案:

答案 0 :(得分:6)

“什么在使用所有这些内存?”

Python对象有开销。查看一些字符串实际占用的字节数:

Python 2:

>>> import sys
>>> map(sys.getsizeof, ('', 'a', u'ä'))
[21, 22, 28]

Python 3:

>>> import sys
>>> list(map(sys.getsizeof, ('', 'a', 'ä')))
[25, 26, 38]

“明智地做这个记忆的更有效方法是什么?”

在评论中你说有很多重复的值,所以string interning(只存储每个不同字符串值的一个副本)可能会有很大帮助。试试这个:

Python 2:

            markers.append(map(intern, line.rstrip().split('\t')))

Python 3:

            markers.append(list(map(sys.intern, line.rstrip().split('\t'))))

注意我还使用line.rstrip()从行中删除了尾随的\n

<强>实验

我试过

>>> x = [str(i % 1000) for i in range(10**7)]

>>> import sys
>>> x = [sys.intern(str(i % 1000)) for i in range(10**7)]
Python中的

3.第一个需要355 MB(查看Windows任务管理器中的过程)。第二个只需47 MB​​。此外:

>>> sys.getsizeof(x)
40764032
>>> sum(map(sys.getsizeof, x[:1000]))
27890

因此40 MB用于引用字符串的列表(毫不奇怪,因为每个字节有一千万个引用。)而琴弦本身只有27 K B。

进一步改进

从实验中可以看出,您的大部分内存使用可能不是来自字符串,而是来自列表对象。您的markers列表对象以及代表您的行的所有列表对象。特别是如果你使用64位Python,我怀疑你这样做。

为了减少这种开销,你可以使用元组代替行的列表,因为它们更轻量级:

sys.getsizeof(['a', 'b', 'c'])
48
>>> sys.getsizeof(('a', 'b', 'c'))
40

我估计你的2 GB文件有8000万行,这样可以节省640 MB RAM。如果运行64位Python,可能会更多。

另一个想法:如果你的所有行都有相同数量的值(假设有三个),那么你可以抛弃那些8000万行列表对象并使用一个2.4亿字符串值的一维列表。您只需使用markers[3*i+j]而不是markers[i][j]来访问它。它可以节省几GB的RAM。