在Python中节省内存。如何高效迭代并保存200万行文件?
我有一个用制表符分隔的数据文件,里面有超过200万行和19列。你可以在这个链接找到它:http://download.geonames.org/export/dump/.
我开始运行以下代码,但用的是for l in f.readlines()
。我知道直接遍历文件应该更高效,所以我把这个方法放在下面。不过,即使这样小小的优化,我的程序还是用了30%的内存,而我只处理了大约6.5%的记录。看起来这样下去,内存又要用完了,就像之前那样。而且,我的函数运行得很慢。有没有什么明显的方法可以加快速度?在每次for
循环中用del
删除对象会有帮助吗?
def run():
from geonames.models import POI
f = file('data/US.txt')
for l in f:
li = l.split('\t')
try:
p = POI()
p.geonameid = li[0]
p.name = li[1]
p.asciiname = li[2]
p.alternatenames = li[3]
p.point = "POINT(%s %s)" % (li[5], li[4])
p.feature_class = li[6]
p.feature_code = li[7]
p.country_code = li[8]
p.ccs2 = li[9]
p.admin1_code = li[10]
p.admin2_code = li[11]
p.admin3_code = li[12]
p.admin4_code = li[13]
p.population = li[14]
p.elevation = li[15]
p.gtopo30 = li[16]
p.timezone = li[17]
p.modification_date = li[18]
p.save()
except IndexError:
pass
if __name__ == "__main__":
run()
编辑,更多细节(看起来很重要):
随着脚本运行并保存更多行,内存消耗在增加。这个方法.save()
是一个经过修改的django模型方法,里面有一个unique_slug的代码片段,它正在写入一个postgresql/postgis数据库。
解决方案:Django中的数据库日志记录会消耗内存。
3 个回答
我觉得这样没问题。像这样逐行读取文件,或者使用 xreadlines()
,会根据需要读取每一行(后台会有合理的缓存处理)。所以,随着你读取的数据越来越多,内存的使用量不应该增加。
至于性能方面,你应该对你的应用进行性能分析。很可能瓶颈出现在更深层的函数里,比如 POI.save()
。
你提供的数据其实没什么好担心的:在你读取越来越多的行时,内存使用量有没有增加?如果有增加,那就值得担心了——不过根据你展示的代码,似乎并没有这种情况,前提是 p.save()
是把对象保存到数据库或文件里,而不是一直占用内存。其实加上 del
语句也没什么实际意义,因为在每次循环的时候,内存都会被回收。
如果有更快的方法来创建一个POI实例,而不是一个个绑定它的属性,那就可以加快速度了。例如,可以把这些属性(可能用关键字参数?用位置参数会更快……)传给POI的构造函数。不过这是否可行就要看 geonames.models
这个模块了,我对此一无所知,所以只能给一些很笼统的建议——比如,如果这个模块允许你一次性保存一堆POI,那你可以试着一次创建100个,然后一起保存,这样应该会提高速度(不过会稍微增加内存使用)。
确保Django的DEBUG设置为False