从一次python程序的性能优化说开去

一门编程语言入门是容易的,至少大家都知道从hello world开始。但这次性能优化的经历告诉我,“换语言”这件事是有门槛的。

这次性能优化是针对数据入库流程中的一个环节(brief)做的。

我们常说解决问题重要,发现问题更重要。没错,这次发现问题就占用了我较长时间。brief部署在X平台上,通过增加日志,我发现brief耗时较长的部分发生在平台内部,接下来主要工作就是找X平台的负责同学沟通了。X平台已经升级到第三代,而我们还停留在第一代,版本低不要紧,关键是问题比较多,对方投入人力少,只找到对应有效的负责同学就费了很大劲(现在知道与时俱进是多么重要了,^-^!)

经过X平台同学的不懈努力,最终定位为brief的吞吐能力不行,导致整体耗时增加。Ok,扫一眼代码,看brief是单线程的,既然吞吐不行,那就改成多线程吧。等等,这就定了方案了?

方法论有问题。需要这么小题大做么?吞吐不行,为啥不先看看单线程慢在哪里呢?C++、java都有对应的profile工具,python估计也有吧。一搜,果然,不仅有,而且使用起来更简单,是python自带的工具。

python -m profile /path/to/your.py

执行结束,程序热点立现。

好吧。确实存在很多CPU计算,不太好优化。转多线程吧。尽管我们最终还是要朝着多线程的方向去思考,但是思路不能断,这有助于培养我们的方法论意识。

多线程能解决问题么? 不能!python解释器内部有一把全局锁GIL(Global interpreter Lock),对于计算密集型程序来说,可认为还是单线程执行,并不能提高程序吞吐。好吧,我一开始并不知道python的多线程是伪多线程,这就涉及到语言设计层面的问题,对于我这种只了解hello world的python程序员,显然发现不了这样的问题。在现在小学生都要普及python教育的时代,我是out了,要加强学习啊。

言归正传,多线程解决不了怎么办?增加并发还是可以使用多进程,从此踏入了不归路。知道python NB的我坚信python肯定有多进程支持,hello world的思想让我在百度很快找到了python多进程demo。把demo搬到brief,执行brief,程序无法退出,CTRL + C后发现,程序在疑似锁等待的位置抛异常了。多进程的生产者消费者模型不好写啊,multiprocessing.Queue竟然没有判断queue关闭的接口,只能自己实现了一套:

queue_closed = multiprocessing.Value('i', 0)

def produce(q, cnt, value, queue_closed):
    while cnt:
        q.put(value)
        cnt = cnt - 1   
    q.close()
    queue_closed.value = 1
    q.join()

def consume(q, queue_closed):
    while True:
        try:
            if queue_closed.value == 1 and q.qsize() == 0:
                break
            value = q.get(timeout=0.01)
            process(value, output_queue)
            q.task_done()
        except Empty:
            logging.warning("get queue item timeout")

死锁问题解决了,利用多进程确实提高brief的吞吐,但另外一个问题来了:日志怎么打?logging支持多线程,但不支持多进程。又是一番搜索,找到几个解决方案,multiprocessing_logging,ConcurrentLogHandler,试了一下又出现一直死锁的问题了,被死锁搞得焦头烂额,这次算是比较常见的问题了:多线程环境下fork,即多进程多线程,fork子进程时把父进程持有的锁也复制了,导致父进程释放锁时,子进程并不能感知这个状态,进而死锁,解决方案先fork子进程,后启动线程。最终,通过ConcurrentLogHandler解决日志问题,ConcurrentLogHandler使用到了文件锁,对性能要求很高的程序慎用(当然,如果实在很高,你该选用C++了)。业界有名的软件nginx采用的是单线程多进程的架构,可以学习一下她的日志打印机制。

至此,brief性能优化告一段落。总结一下:

  • 学习一门新的语言,从更高层次去了解它的设计思想或许是一种更有效的学习方式,毕竟思想比hello world更通用
  • 学习业界著名开源软件设计思想
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值