我编写了一段简单的代码片段来处理一个文本文件,其中每行包含一个带有PoS标记词的短语(例如I / noun am / verb),我想分别提取单词和标签:
splitted_sentences = []
splitted_pos = []
with open("my_path", "r") as tagged_sentences:
for sentence in tagged_sentences:
curr_sentence = []
curr_pos = []
for tag in sentence.strip().split(" "):
splitted_tag = tag.split("/")
word = splitted_tag[0]
pos = splitted_tag[1]
curr_sentence.append(word)
curr_pos.append(pos)
splitted_sentences.append(curr_sentence)
splitted_pos.append(curr_pos)
代码按预期工作,但是,当循环执行远远超过预期时,内存ram消耗永远不会停止增加(文本文件大约为100MB,RAM达到5GB的峰值消耗)。我尝试过使用一些内存分析工具,看起来我正在创建数千个列表引用(可能是curr_sentence和curr_pos列表)。解决这个问题的正确方法是什么?在运行内存泄漏时?
答案 0 :(得分:2)
splitted_sentences
是字符串列表的列表。列表的内存开销约为70字节,字符串约为40字节。假设平均字/ POS是5个字节,平均句子是10个字/ pos对,100MB文件是1M个句子* 10个字* 1个字符串=(1M * 70)*(10 * 40)= 28Gb的内存,如果所有字符串都是唯一的。显然,其中许多都不是,但这种内存消耗可以在没有内存泄漏的情况下解释。
我解决这个问题的方法是顺序处理。我怀疑你真的需要同时在内存中的所有这些数据。用发电机替换主回路可能会改变游戏规则:
def sentence_gen(fname):
for sentence in open(fname, 'r'):
yield [pair.split("/", 1) for pair in sentence.strip().split()]
答案 1 :(得分:0)
将curr_sentence和curr_pos移到for循环之外。然后你可以清除而不是创建新的。我的猜测是,出于某种原因,在for循环结束时没有删除curr_sentence和curr_pos列表。
通过在for循环之外移动这些列表,您不会在每次迭代时创建新的列表。