使用 cProfile 和火焰图调优 Python 程序性能(下)

简介: 使用 cProfile 和火焰图调优 Python 程序性能

Python 中有一个第三方包(见参考文献)可以直接从 cProfile 的结果生成火焰图:

  1. 在原有的代码中加上一句: pr.dump_stats("pipeline.prof")
  2. 调用该工具: flameprof pipeline.prof>pipeline.svg

然后打开 SVG 文件就可以了:640 (6).jpg其中火焰的宽度代表了运行的时长,我们现在的优化目标就是这些耗时比较长的步骤。

可以看大其中 mysql 的访问占了绝对的大头,按理说跑100次的话,不应该每次都花费时间在建立连接上啊,这里一定有问题。经过排查发现在某处链接是使用了 close_old_connections 来保证不会抛出数据库断开的异常,这还是在头条带来的习惯。。closeoldconnections 的功能是关闭已经失效的链接,看来我的理解还是有误的。先把这块删掉,最终解决应该是这块放到一个队列里,统一存入数据库。

去掉之后:640 (7).jpg现在的大头又变成 lxml 的,又动了优化它的心思,lxml 是 libxml2 的一个 Python binding,查了下应该是最快的 html parser 了,这块真的没有什么优化空间。盯了一会儿,眼睛最终看到了一个小角落:  640 (8).jpg

一个正则匹配居然占用了 8% 的运行时间,太不像话了。老早之前就听说 Python 的标准库正则性能不行,现在才发现原来是真的挺差劲的。Python 标准库的 re 模块采用的是 PCRE 的处理方式,而采用 NFA 的处理方式的正则要快很多,这块还需要再看一下。不过眼下倒是可以直接换一个库来解决。regex 模块是 re 模块的一个 drop-in replacement.

pip install regex and importregexasre,就搞定了640 (9).jpg可以看到正则那块直接消失了。提升还是很大的。时间不早了,当天的优化就到此结束了。上线之后,积压一下子就下去了:640 (10).jpg

后记

要想调试的时候方便,在写代码的时候就要注意,尽量使自己的代码 mock-friendly 一点。如果需要引入外部的数据库、服务、API等等各种资源,最好有一个开关或者选项能够不加载外部资源,或者至少能够很方便地 mock 这些外部服务,这样方便对每一个小单元进行 profile。

总有人吐槽 Python 的性能低下,但是 Python 本来就不是做计算任务的呀,Python 是一门胶水语言,是用来写业务逻辑的,而不是用来写CPU密集的算法的。事实上复杂的解析一般都会用 C++ 这种硬核语言来写了,比如 numpy TensorFlow lxml。大多数程序员一天 90% 的工作除了和产品经理撕逼以外,也就是在写 CRUD,也就是调用这些包。所以瓶颈一般在 IO 上而不在 CPU 上,而解决 IO 的瓶颈手段就多了,Python 中至少有 多进程、多线程、AsyncIO、Gevent 等多种方法。不过方法多其实也是一个弊端,这几种方法可以说是基本互不兼容,对各种第三方库的支持也参差不齐。而 Go 在这方面就做地很好了,语言直接内置了 go 关键字,甚至都不支持多线程。所有的库都是支持一个统一的并发模型,对于使用者来说更简单。

Zen of Python 中有一句:There should be one way -- preferably only one way -- to do a thing. 这点上 Python 本身没有做到,反倒是 Go 实践地非常好。

扯远了,程序的瓶颈其实不外乎CPU、内存和 IO 三个方面,而 cProfile 和火焰图是判断 CPU 瓶颈的一把利器。

后面还发现了一些性能瓶颈,也列在这里:

  1. yaml 的反序列化时间过长。解决方法是添加了一个 Expiring LRU Cache,不要每次都去加载,当然牺牲的是一点点内存,以及当规则变更时会有一些延迟,不过都是可以接受的。之前早就听人说 Thrift 的序列化性能相比 Protobuf 太低,现在想想序列化和反序列化还真是一个很常见的性能瓶颈啊。
  2. 存储使用了 360 的 pika,pika 可以理解为一个基于 rocksdb 的硬盘版 redis。最开始的时候没多想,随便找了台机器搭了起开,把上面的问题解决之后,pika 的延迟很快大了起来,机器的监控也显示 IO 基本被打满了。这时候才发现原来这台机器没有用 SSD,果断换了 SSD 问题基本解决了。如果再有问题可能就需要集群了。

性能这个问题其实是典型的木桶理论的场景,系统的整体性能是由最差的一块决定的。所以也是一个不断迭代的过程。

目录
相关文章
|
4月前
|
机器学习/深度学习 数据采集 算法
Python AutoML框架选型攻略:7个工具性能对比与应用指南
本文系统介绍了主流Python AutoML库的技术特点与适用场景,涵盖AutoGluon、PyCaret、TPOT、Auto-sklearn、H2O AutoML及AutoKeras等工具,帮助开发者根据项目需求高效选择自动化机器学习方案。
367 1
|
6月前
|
数据采集 测试技术 C++
无headers爬虫 vs 带headers爬虫:Python性能对比
无headers爬虫 vs 带headers爬虫:Python性能对比
|
2月前
|
数据采集 存储 Web App开发
Python爬虫库性能与选型实战指南:从需求到落地的全链路解析
本文深入解析Python爬虫库的性能与选型策略,涵盖需求分析、技术评估与实战案例,助你构建高效稳定的数据采集系统。
250 0
|
5月前
|
人工智能 并行计算 开发者
CUDA重大更新:原生Python可直接编写高性能GPU程序
NVIDIA在2025年GTC大会上宣布CUDA并行计算平台正式支持原生Python编程,消除了Python开发者进入GPU加速领域的技术壁垒。这一突破通过重新设计CUDA开发模型,引入CUDA Core、cuPyNumeric、NVMath Python等核心组件,实现了Python与GPU加速的深度集成。开发者可直接用Python语法进行高性能并行计算,显著降低门槛,扩展CUDA生态,推动人工智能、科学计算等领域创新。此更新标志着CUDA向更包容的语言生态系统转型,未来还将支持Rust、Julia等语言。
370 3
CUDA重大更新:原生Python可直接编写高性能GPU程序
|
5月前
|
网络协议 API 开发者
分析http.client与requests在Python中的性能差异并优化。
合理地选择 `http.client`和 `requests`库以及在此基础上优化代码,可以帮助你的Python网络编程更加顺利,无论是在性能还是在易用性上。我们通常推荐使用 `requests`库,因为它的易用性。对于需要大量详细控制的任务,或者对性能有严格要求的情况,可以考虑使用 `http.client`库。同时,不断优化并管理员连接、设定合理超时和重试都是提高网络访问效率和稳定性的好方式。
124 19
|
4月前
|
网络协议 API Python
解析http.client与requests在Python中的性能比较和改进策略。
最后,需要明确的是,这两种库各有其优点和适用场景。`http.client` 更适合于基础且并行的请求,`requests` 则因其易用且强大的功能,更适用于复杂的 HTTP 场景。对于哪种更适合你的应用,可能需要你自己进行实际的测试来确定。
120 10
|
9月前
|
测试技术 数据库 Python
Python装饰器实战:打造高效性能计时工具
在数据分析中,处理大规模数据时,分析代码性能至关重要。本文介绍如何使用Python装饰器实现性能计时工具,在不改变现有代码的基础上,方便快速地测试函数执行时间。该方法具有侵入性小、复用性强、灵活度高等优点,有助于快速发现性能瓶颈并优化代码。通过设置循环次数参数,可以更准确地评估函数的平均执行时间,提升开发效率。
235 61
Python装饰器实战:打造高效性能计时工具
|
7月前
|
缓存 并行计算 数据处理
全面提升Python性能的十三种优化技巧
通过应用上述十三种优化技巧,开发者可以显著提高Python代码的执行效率和性能。每个技巧都针对特定的性能瓶颈进行优化,从内存管理到并行计算,再到使用高效的数值计算库。这些优化不仅能提升代码的运行速度,还能提高代码的可读性和可维护性。希望这些技巧能帮助开发者在实际项目中实现更高效的Python编程。
516 22
|
9月前
|
并行计算 安全 Java
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解GIL仍至关重要。
565 16
Python GIL(全局解释器锁)机制对多线程性能影响的深度分析
|
7月前
|
Python
[oeasy]python074_ai辅助编程_水果程序_fruits_apple_banana_加法_python之禅
本文回顾了从模块导入变量和函数的方法,并通过一个求和程序实例,讲解了Python中输入处理、类型转换及异常处理的应用。重点分析了“明了胜于晦涩”(Explicit is better than implicit)的Python之禅理念,强调代码应清晰明确。最后总结了加法运算程序的实现过程,并预告后续内容将深入探讨变量类型的隐式与显式问题。附有相关资源链接供进一步学习。
95 4

推荐镜像

更多