作为Java和python这类相对设计比较完善的解释型语言而言,总有很严密的垃圾回收机制用以防止资源被浪费甚至内存溢出之类的问题。起先我始终认为这会大大提升系统的性能,然而这次碰上了悖论。
刚过完春节,春节前,考虑到会有很多人发送贺卡,邮件系统的压力剧增。同时春节期间无人值守,没有办法人为干预很多。于是我打包了之前的一段python程序用来在节日期间发送大量的邮件贺卡。
初次测试的过程中,由于仅仅只是测试下性能如何,没有“特别规矩”没有关闭定义的类,于是代码大致如此:
for mailBody in mailList: mail = SendMail() mail.MailServer['UserName'] = username mail.MailServer['Password'] = password mail.MailServer['Host'] = host mail.MailServer['port'] = port mail.SenderName = senderName mail.Charset = 'UTF-8' mail.AddMeta('Precedence', 'bulk') delFromDb(mailBody[3]) try : mail.Send(From = smtpFrom, Address = mailBody[0], Subject = mailBody[1], Body = mailBody[2]) logging.info('<a title="Mail" href="http://www.litrin.net/tag/mail/">Mail</a> send to: ' + mailBody[0] + " with subject is " + mailBody[1] + " By thread #" + str(thread)) except: logging.error('Error send to: ' + mailBody[0] + " with subject is " + mailBody[1] +"By thread #" + str(thread))
初版测试了一下,每小时的发送量保守达到2w左右。已经达到了要求,可以正式部署。
考虑到了生产环境中的服务器负载很高,于是对python的代码提出了更高的要求,在上述代码的最后加上了一句:
mail = None
结束发送循环以后立即释放 SendMail()这个类占据的资源。这是一个程序员都应该遵守的好习惯。部署好了以后,再次测试,每小时仅能发送不足7000。性能仅有之前的30%。
多次拉锯测试,只要加上那句mail=None,性能就会下降。所有的性能缺陷都指向了这句“好习惯”。没什么说的,直接在头部加上
import gc gc.disable()
加不加那句已经没有实质性的影响了。
Python不同于Java的垃圾回收机制,Java机制是只有等到资源,特别是内存资源紧张的情况下才会执行垃圾回收机制。而Python则是忠实于C++系的逻辑,只要资源没有被引用就回自动被回收机制无情的回收。
在这个例子中,由于Sendmail的类相对比较复杂的操作,每次构建和解构的过程都需要花费较长时间。而且由于Sendmail是主循环,占用了大量的内存,每次垃圾的回收系统都会重新整理内存碎片,如果每次都为释放内存而手工解构的话性能反而会大大降低。
转载请注明:爱开源 » Python的垃圾回收机制