如何优化打开和读取多次相同文件的python脚本?
Posted
技术标签:
【中文标题】如何优化打开和读取多次相同文件的python脚本?【英文标题】:How to optimize a python script which opens and reads multiple times the same files? 【发布时间】:2014-03-01 17:34:39 【问题描述】:我有一个运行良好的代码,但它占用了太多内存。
本质上,这段代码采用一个输入文件(我们称之为索引,即 2 列制表符分隔)在第二个输入文件(我们称其为数据,即 4 列制表符分隔)中搜索相应的术语在第一列中,然后将其替换为索引文件中的信息。
索引的一个例子是:
amphibian anm|art|art|art|art
anaconda anm
aardvark anm
数据的一个例子是:
amphibian-n is green 10
anaconda-n is green 2
anaconda-n eats mice 1
aardvark-n eats plants 1
因此,将数据的Col 1中的值替换为Index中对应的信息时,结果如下:
anm-n is green
art-n is green
anm-n eats mice
anm-n eats plants
我将代码分成多个步骤,因为这个想法是计算给定数据文件中第 2 列和第 3 列的替换项(数据中的第 4 列)的值的平均值。此代码获取数据文件中插槽填充器的总数,并对步骤 3 中使用的值求和。
期望的结果如下:
anm second hello 1.0
anm eats plants 1.0
anm first heador 0.333333333333
art first heador 0.666666666667
我在步骤 1、2 和 3 中多次打开同一个输入文件(即 3 次),因为我需要创建几个需要按特定顺序创建的字典。 有没有办法优化我打开同一个输入文件的次数?
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import division
from collections import defaultdict
import datetime
print "starting:",
print datetime.datetime.now()
mapping = dict()
with open('input-map', "rb") as oSenseFile:
for line in oSenseFile:
uLine = unicode(line, "utf8")
concept, conceptClass = uLine.split()
if len(concept) > 2:
mapping[concept + '-n'] = conceptClass
print "- step 1:",
print datetime.datetime.now()
lemmas = set()
with open('input-data', "rb") as oIndexFile:
for line in oIndexFile:
uLine = unicode(line, "latin1")
lemma = uLine.split()[0]
if mapping.has_key(lemma):
lemmas.add(lemma)
print "- step 2:",
print datetime.datetime.now()
featFreqs = defaultdict(lambda: defaultdict(float))
with open('input-data', "rb") as oIndexFile:
for line in oIndexFile:
uLine = unicode(line, "latin1")
lemmaTAR, slot, filler, freq = uLine.split()
featFreqs[slot][filler] += int(freq)
print "- step 3:",
print datetime.datetime.now()
classFreqs = defaultdict(lambda: defaultdict(lambda: defaultdict(float)))
with open('input-data', "rb") as oIndexFile:
for line in oIndexFile:
uLine = unicode(line, "latin1")
lemmaTAR, slot, filler, freq = uLine.split()
if lemmaTAR in lemmas:
senses = mapping[lemmaTAR].split(u'|')
for sense in senses:
classFreqs[sense][slot][filler] += (int(freq) / len(senses)) / featFreqs[slot][filler]
else:
pass
print "- step 4:",
print datetime.datetime.now()
with open('output', 'wb') as oOutFile:
for sense in sorted(classFreqs):
for slot in classFreqs[sense]:
for fill in classFreqs[sense][slot]:
outstring = '\t'.join([sense, slot, fill,\
str(classFreqs[sense][slot][fill])])
oOutFile.write(outstring.encode("utf8") + '\n')
有关如何优化此代码以处理大型文本文件(例如 >4GB)的任何建议?
【问题讨论】:
优化标准是什么? 我正在尝试处理一个 4 GB 的文件。它在步骤 2 中某处的 16GB 服务器上的内存不足。我希望能够使用服务器中的 16GB 内存来处理整个文件。你有什么建议? 这对您来说可能是不可能的,但是对于这类事情来说,实际的数据库不是更好的选择吗? 【参考方案1】:如果我正确理解代码,则不需要引理集。您可以删除第 1 步并替换第 3 步中的检查
if lemmaTAR in lemmas:
直接用
if mapping.has_key(lemmaTAR):
关于内存问题 - 您是否尝试过减少保存在内存中的数据的开销?目前您正在使用嵌套字典。也许平面数据结构会使用更少的内存,例如一维featFreqs,它采用由“%slot-%filler”构造的单个键。
【讨论】:
谢谢,这真的解决了我的问题。除了按照您的建议删除第 1 步并替换第 3 步中的检查外,我还删除了所有 unicode 变量并将 featFreq 中的float
更改为 int
。通过这些更改和您的建议,我能够在大约 16GB 的内存中处理整个文件(4GB)。 30 分钟。以上是关于如何优化打开和读取多次相同文件的python脚本?的主要内容,如果未能解决你的问题,请参考以下文章
在具有不同输入的 1x exe 中同时多次运行 python 脚本
如何在 C# .NET 中保持 TCP 连接打开并执行多次写入/读取?