在Python中节省内存。如何高效迭代并保存200万行文件?

3 投票
3 回答
1269 浏览
提问于 2025-04-15 20:24

我有一个用制表符分隔的数据文件,里面有超过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 个回答

2

我觉得这样没问题。像这样逐行读取文件,或者使用 xreadlines(),会根据需要读取每一行(后台会有合理的缓存处理)。所以,随着你读取的数据越来越多,内存的使用量不应该增加。

至于性能方面,你应该对你的应用进行性能分析。很可能瓶颈出现在更深层的函数里,比如 POI.save()

2

你提供的数据其实没什么好担心的:在你读取越来越多的行时,内存使用量有没有增加?如果有增加,那就值得担心了——不过根据你展示的代码,似乎并没有这种情况,前提是 p.save() 是把对象保存到数据库或文件里,而不是一直占用内存。其实加上 del 语句也没什么实际意义,因为在每次循环的时候,内存都会被回收。

如果有更快的方法来创建一个POI实例,而不是一个个绑定它的属性,那就可以加快速度了。例如,可以把这些属性(可能用关键字参数?用位置参数会更快……)传给POI的构造函数。不过这是否可行就要看 geonames.models 这个模块了,我对此一无所知,所以只能给一些很笼统的建议——比如,如果这个模块允许你一次性保存一堆POI,那你可以试着一次创建100个,然后一起保存,这样应该会提高速度(不过会稍微增加内存使用)。

5

确保Django的DEBUG设置为False

撰写回答