垃圾回收机制与 python 性能调优

来源:互联网 发布:局域网限速软件 编辑:程序博客网 时间:2024/04/27 18:52

这两天在调试一个耗时大户的数据载入模块,因为时间的耗费居然主要都花在数据载入、解析、格式化上了,虽然处理的是很大量的数据,但还是心有不甘,不解决它使得后面的算法调试工作很难快捷深入的进行下去。

通过profile检查之后,把调试的目标锁定为文本解析的那一行代码上。因为数据的导出虽有几秒的耗时,但导出后数据的解析才是大头,只是这么一句简单的语句:

[row.split(',') for row in records]

很显然地,我会毫不犹豫地把罪魁祸首指定在split的身上。于是试图采用其它的方法来取代它,无论map还是直接取切片的方式都试过,就差没有用C来重写split函数了。但收效甚微。我甚至考虑把数据源切换到mysql,以避免做数据split这一步,但mysql的大数据量导出速度让我无法忍受。

无意中我用time.time()来计算了一下时间,很令人郁闷又很令人惊喜地发现,包含该行解析语句的子程序会越跑越慢。每次处理100W行的记录,第一次7秒,第二次14秒。如果从整个程序来启动这个模块,更加无法让人接受:7、15、50+、100+、200+。如果你的子程序运行得一次比一次慢,你会感觉生活很没有盼头。但我似乎找到真正的原因了:慢不是因为它本来就慢,而是在做同样的事情,却变得越来越慢。

于是想起以前Davies给我推荐过的一篇文章,讲python的垃圾回收(Garbage Collection)机制对程序性能的影响。当时由于主要并不是那个原因,所以没有太多研究。但这次的现象我可以原原本本地对上号,很有可能是因为数据量太大,处理过程中留下太多暂时不能清除的变量,而python的垃圾回收却在一遍一遍地扫这些不断在增长的列表,导致程序受到的影响越来越大。赶紧证实一下,import gc,然后在数据载入模块前gc.disable(),结束后再gc.enable()。结果原来要跑将近两个小时的程序,这下不用5分钟就跑完了。cool~!用gc.get_count()也证明了之前的猜想,在第一次运行之后临时变量数目就从几百上升到百万,并一直在涨。

由此我想,是不是有很多python新手对python速度的责难,都是因为这个原因呢(其实我觉得python基本模块的速度还是很快的:-))。另外,如果你的python程序在处理大数据量的问题,并且出现某个子程序在做同样量的工作,却越跑越慢的情况,恭喜你,你也许可以在这里对号入座,找到答案了。

关于作者

阿稳, 豆瓣, 算法工程师
推荐系统;数据挖掘;算法架构及实现的可扩展性;R环境编程 如果你的问题已经能从我的博客中得到解答,就最好不过了:http://www.wentrue.net/blog/

原创粉丝点击