首页 > 解决方案 > 如何以内存有效的方式逐个元素地存储读入的数据?

问题描述

我正在处理的程序需要读取 ASCII 格式的数据文件,这些文件可能非常大(最多 5GB)。格式可能会有所不同,这就是我想出 using 的原因readline(),拆分每一行以获得纯条目,将它们全部附加到一个大的字符串列表中,然后根据某些标记词的出现将其划分为较小的字符串列表,然后将数据传递给程序内部的数据结构,以便进一步统一处理。这种方法效果很好,只是它需要大量内存,我想知道为什么。

所以我写了这个小测试用例,让你理解我的问题:这里的输入数据是莎士比亚罗密欧与朱丽叶的文本(实际上我希望混合字母 - 数字输入) - 请注意,我希望你自己复制数据以保留内容清楚地。该脚本会生成一个 .txt 文件,然后使用该文件再次读取该文件。在这种情况下,原始内存大小为153 KB。使用...读取此文件

由于这些数字在这种情况下似乎不是问题,因此对于以 GB 为顺序的输入数据,RAM 需求增加大于 10 的因子肯定是一个因子。

我不知道为什么会这样或如何避免这种情况。从我的理解来看,列表只是指向存储在列表中的所有值的指针结构(这也是为什么列表上的 sys.getsizeof() 会给出“错误”结果的原因)。对于值本身,如果我有“LONG STRING”或“LONG”+“STRING”,它不应该对内存产生影响,因为它们都使用相同的字符,这应该导致相同数量的位/字节。

也许答案真的很简单,但我真的被这个问题困住了,所以我很感谢每一个想法。

# step1: http://shakespeare.mit.edu/romeo_juliet/full.html
# step2: Ctrl+A and then Ctrl+C
# step3: Ctrl+V after benchmarkText

benchmarkText = """ >>INSERT ASCII DATA HERE<< """

#=== import modules =======================================
from pympler import asizeof
import sys

#=== open files and safe data to a structure ==============
#-- original memory size
print("\n\nAll memory sizes are in KB:\n")
print("Original string size:")
print(asizeof.asizeof(benchmarkText)/1e3)
print(sys.getsizeof(benchmarkText)/1e3)

#--- write bench mark file
with open('benchMarkText.txt', 'w') as f:
    f.write(benchmarkText)

#--- read the whole file (should always be equal to original size)
with open('benchMarkText.txt', 'r') as f:
    # read the whole file as one string
    wholeFileString = f.read()    
    # check size:
    print("\nSize using f.read():")
    print(asizeof.asizeof(wholeFileString)/1e3)

#--- read the file in a list
listOfWordOrNumberStrings = []
with open('benchMarkText.txt', 'r') as f:
    # safe every line of the file
    listOfLineStrings = f.readlines()
    print("\nSize using f.readlines():")
    print(asizeof.asizeof(listOfLineStrings)/1e3)

    # split every line into the words or punctation marks
    for stringLine in listOfLineStrings:
        line = stringLine[:-1] # get rid of the '\n'
       # line = re.sub('"', '', line) # The final implementation will need this, however for the test case it doesn't matter.
        elemsInLine = line.split()
        for elem in elemsInLine:
            listOfWordOrNumberStrings.append(elem)
    # check size
    print("\nSize after splitting:")
    print(asizeof.asizeof(listOfWordOrNumberStrings)/1e3)

(我知道我在这里使用 readlines() 而不是 readline() - 我为这个测试用例更改了它,因为我认为它使事情更容易理解。)

标签: pythonlistmemorysplitreadlines

解决方案


推荐阅读