运行很长时间并占用大量内存后,Python性能会出现奇怪的下降

运行很长时间并占用大量内存后,Python性能会出现奇怪的下降,python,macos,Python,Macos,我写了一个程序来处理大约220万条记录的数据。对于每条记录,它将通过一系列的20次计算,总共大约需要0.01秒。为了让它运行得更快,我使用Python多进程,将数据分成6个块,并与主进程并行运行,主进程向进程分配有效负载并协调执行。顺便说一句,作为计算的结果,该程序将向数据库写入大约2200万条记录 我在MacBookPro i7 2.2GHz上运行它,在Python 3.2.2上运行8GB RAM。数据位于本地MySQL服务器上 程序一开始运行良好,CPU平均利用率为60-70%,我的Macb

我写了一个程序来处理大约220万条记录的数据。对于每条记录,它将通过一系列的20次计算,总共大约需要0.01秒。为了让它运行得更快,我使用Python多进程,将数据分成6个块,并与主进程并行运行,主进程向进程分配有效负载并协调执行。顺便说一句,作为计算的结果,该程序将向数据库写入大约2200万条记录

我在MacBookPro i7 2.2GHz上运行它,在Python 3.2.2上运行8GB RAM。数据位于本地MySQL服务器上

程序一开始运行良好,CPU平均利用率为60-70%,我的Macbook Pro就像烤箱一样热。然后,在运行大约5小时后,CPU利用率会降低到每个核心的平均20%。我当时的一些观察是: -每个Python进程消耗大约480 MB的真实RAM和大约850 MB的虚拟RAM。这些繁重的过程总共有6个 -OSX消耗的总虚拟内存(如活动监视器所示)约为300GB

我怀疑性能下降是由于巨大的内存消耗和潜在的高页面交换

如何更好地诊断这些症状? Python长时间运行大型内存对象有问题吗?真的,我不认为运行6小时对于今天的技术来说是很沉重的,但见鬼,我只有大约半年的Python经验,所以。。。我知道什么


谢谢

我猜性能下降是因为它在内存中交换内容。我认为问题不在于程序运行多长时间——Python使用垃圾收集器,因此它没有内存泄漏

嗯,这不完全是真的。垃圾收集器将确保删除任何无法访问的内容。(换言之,它不会删除您可以访问的内容。)但是,它不够智能,无法检测数据结构何时不会用于程序的其余部分;您可能需要通过将对它的所有引用设置为
None
来进行澄清,以使其正常工作

  • 你能把涉及的代码贴出来吗

  • 这是一个您需要多次给定记录的程序吗?加载记录的顺序对程序重要吗

  • 如果python进程只分配了几GB的内存,那么为什么要使用300 GB的内存呢


  • 对不起,代码太长了,我来解释一下设计。程序使用了大量的生成器函数,因为下一个值计算总是需要一些早期的值/状态。从db记录的读取到20次计算,每一次都是通过封装在各自对象中的生成器函数来执行的。目前我有大约1000(不同的数据流)x20(计算)对象。每个数据流都是一个不同的产品,我通过按时间顺序进行迭代,对它们进行回归和分析。我不知道,这就是为什么我将这个问题标记为Python和OSX:)我对Python很陌生,有没有关于如何解决内存和性能问题的好指南?我想我找到了问题所在。在Python进程中,查询220万条记录实际上占用了2.6GB的内存。显然,pymysql驱动程序不支持(或者我可能错误地使用了它)通过开放游标连接从DB检索数据。我怀疑它会在返回第一条记录之前缓存完整的结果集。我想知道您是否能够使用存储过程在数据库本身上进行这些计算,并消除中间层和网络延迟。220万条记录需要大量字节才能来回移动,仅仅是为了进行一些计算。数据库可以做到吗?我已经考虑过这个选项,但没有。我选择Python的原因是编程速度。这一系列的20次计算仅仅是一个开始,而且可能会迅速增长。将它们作为存储过程可能会解决我现在的性能问题,但它会在实现额外的计算插件逻辑方面降低我的速度。我还试着注释掉2200万条记录的db回写,这没有多大帮助。无论你决定走哪条路,听起来你都必须这样做,并分块提交。2.2M记录的回滚段太大。我创建了一个生成器函数,使用运行“select*from table order by date”的光标读取220万rec。然后我遍历游标并批处理数据(通过检测日期变化),然后使用yield一次返回一批数据。一个批处理的最大记录数约为1000,我假设内存将被垃圾收集,因为所有OBJ都是本地函数作用域。我知道像JavaJDBC这样的其他语言有游标类型,可以将所有数据读入内存以支持随机访问。我最初怀疑这可能是我的游标的默认行为,但我现在不这么认为。