一、需求背景

性能压测时,发现某接口存在性能瓶颈,期望借助工具定位该瓶颈,最好能定位至具体慢方法。

二、cProfile 简介

cProfile 是 Python 标准库中的一个模块,用于对 Python 程序进行性能分析,它能输出每个函数的调用次数、执行耗时等详细信息,可帮助开发者识别程序中运行缓慢的方法,以便进行性能优化,适合作为上述需求的解决方案。

此外,Python 还内置了使用纯 Python 实现的 profile 模块,与 cProfile 功能一样,只不过 cProfile 是用 C 语言编写,性能更高、开销更小,适合在性能敏感的环境(如线上生产环境)中使用。profile 是纯 Python 实现的模块,性能开销相对较大,但因其用 Python 编写,易于理解和修改,适合学习时使用。

三、使用方法

cProfile 支持三种使用方法,一是硬编码于代码中;二是在 Python 应用启动时加载 cProfile 模块;三是通过 IDE(PyCharm)运行。开发环境建议采用方法三,因其简单易用且结果图表丰富;生产环境建议采用方法二,此方法对代码无侵入性。

1. 硬编码于代码中

示例代码:

import cProfile

def my_function():
# Some code to profile
pass profiler = cProfile.Profile()
profiler.enable()
my_function()
profiler.disable()
profiler.print_stats()

执行结果:

2 function calls in 0.000 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 test.py:3(my_function)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

结果字段说明:

ncalls:函数调用的次数。

tottime:在该函数中花费的总时间,不包括调用子函数的时间。

percall:tottime 除以 ncalls。

cumtime:该函数及其所有子函数中花费的总时间。

percall:cumtime 除以原始调用次数。

filename:lineno(function):函数所在的文件名、行号和函数名。

2. 在 Python 应用启动时加载 cProfile 模块

示例代码:

python -m cProfile my_script.py # 方法一、将结果输出至控制台
python -m cProfile -o output.prof my_script.py # 方法二、将结果保存到指定的prof文件

可使用 snakeviz 插件(安装方法为pip install snakeviz)分析 prof 文件。执行snakeviz output.prof后,会将结果挂载到 web 容器中,支持通过 URL(如http://127.0.0.1:8080/snakeviz/xxxoutput.prof)访问。

3. 通过 IDE(PyCharm)运行

使用方法:

通过菜单 [run] > [profile 'app'](其中 app 为应用名称,下同)启动应用。待应用执行完毕且停止后,相关面板会输出相应的调用统计与调用链。

调用统计:

表头“Name”表示被调用的模块或函数;“Call Count”表示被调用次数;“Time (ms)”表示耗时及百分比,时间单位为毫秒。

点击表头列名可对该列进行排序。

在调用统计中,选择“name”列的单元格,右键选中“Navigate to Source”或“Show on Call Graph”,可打开其源码或对应的调用链及位置。

调用链:

此外,通过菜单 [run] > [Concurrency Diagram 'app'] 启动程序,可查看到线程和异步协程(Asyncio)的调用情况,如下图所示:

四、相关配置项

1. cProfile

[root@test bin]# python3 -m cProfile -h
Usage: cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ... Options:
-h, --help show this help message and exit
-o OUTFILE, --outfile=OUTFILE
Save stats to <outfile> # 将分析结果输出到指定的文件中。
-s SORT, --sort=SORT Sort order when printing to stdout, based on pstats.Stats class # 指定输出结果的排序方式。可以根据不同的字段进行排序,如 time, cumulative, calls 等。
-m Profile a library module # 分析一个模块,而不是一个脚本文件

2. snakeviz

[root@test bin]# snakeviz --help
usage: snakeviz [-h] [-v] [-H ADDR] [-p PORT] [-b BROWSER_PATH] [-s] filename Start SnakeViz to view a Python profile. positional arguments:
filename Python profile to view options:
-h, --help show this help message and exit
-v, --version show program \`s version number and exit
-H ADDR, --hostname ADDR hostname to bind to (default: 127.0.0.1) # 用于指定绑定的主机名,默认值为 127.0.0.1,即本地主机。
-p PORT, --port PORT port to bind to; if this port is already in use a free port will be selected automatically (default: 8080) # 用于指定绑定的端口。如果指定的端口已被占用,程序将自动选择一个空闲端口。默认值为 8080。
-b BROWSER_PATH, --browser BROWSER_PATH name of webbrowser to launch as described in the documentation of Python\'s webbrowser module: https://docs.python.org/3/library/webbrowser.html # 按照 Python 的 webbrowser 模块的文档描述,指定要启动的浏览器名称。用户可以通过指定浏览器的路径来控制使用哪个浏览器打开应用。
-s, --server start SnakeViz in server-only mode--no attempt will be made to open a browser # 仅在服务器模式下启动 SnakeViz,不会尝试打开服务器中的浏览器。对于非图形化或不带浏览器的服务器非常有用。

五、生产环境使用示例

生产环境系统版本为 CentOS 7.9.2009 (Core),内核为 5.15.81,使用 4 核 4G 的容器运行DB-GPT controller 子系统。

1. 使用步骤

(1)执行脚本:/usr/local/bin/python3.10 -m cProfile -o out.prof /usr/local/bin/dbgpt start controller &,在 Python 应用启动时加载 cProfile 模块。

(2)执行相关接口压测。

(3)正常停止应用,生成性能分析结果文件(out.prof)。注意:性能分析结果只能是在程序正常停止后才能输出。常规两种做法:其一、后台守护进程,可以使用 kill -2 {应用 PID};其二、前台进程,通过 Ctrl + C 退出。

(4)使用snakeviz -H 0.0.0.0 -s out.prof分析结果文件(其中 -s 仅在服务端模式下运行,不会尝试打开服务器浏览器,一般情况下服务器不自带浏览器;-H 0.0.0.0,支持监听网卡所有接口),执行成功后,会输出可访问的 URL 地址,通过外部或本地浏览器打开。

2. 结果分析

使用外部或本地浏览器访问 snakeviz 生成的 URL 地址。结果如下:

结果说明:

(1)结果包含两部分,即上图和下表。上图展示选中方法及其子方法的调用关系、耗时及占比;下表展示所有方法及其总调用次数(ncalls)、方法本身总耗时(tottime)、方法本身平均耗时(percall)、方法及其子方法总耗时(cumtime)、方法及其子方法平均耗时(percall)以及方法所在文件位置及其行列号。

使用说明:

(1)表格任意列支持升降序操作,选中任意行,页面上方的图形会自动展示该方法及其子方法的调用关系、耗时及占比。

(2)单击图形中的任意子模块,可查看子模块所在方法及其子方法的调用关系、耗时及占比。

分析建议:

(1)选择 cumtime 列降序,选择入口代码,逐步细看,分析瓶颈点。

(2)使用 Sunburst 图样展示,更易体现各方法耗时占比。

3. 评估加载 cProfile 对性能的影响

我们用 Jmeter 对未加载以及加载 cProfile 模块的 Python 应用性能进行评估,以判断生产环境加载 cProfile 对性能的影响程度。结果如下:

配置 Jmeter 压测线程数 CPU 使用率 吞吐量 平均响应时间
CASE1 某应用未加载 cProfile 20 接近单核 100% 527 36ms
CASE2 某应用加载 cProfile 后 20 接近单核 100% 395 49ms

从上表可知,加载 cProfile 后,应用吞吐量下降 25%,平均响应时间增加 13ms,对性能有一定影响。

五、遇到问题

1. kill -15 {应用 PID} 无法生成性能分析结果文件

由于 cProfile 仅支持监听中断(SIGINT)信号,导致 kill 15 发送 SIGTERM 信号时,无法生成性能分析结果文件。

解决办法:使用 kill -2 {应用 PID}。

六、使用总结

(1)cProfile 可以生成详细的性能分布和调用链,非常适合作为分析和定位 Python 应用性能瓶颈的工具。

(2)由于生成性能分析结果文件需要停止应用,且对性能损耗较大(吞吐量降低 25%),所以一般情况下不建议在生产环境直接使用。不过可以使用流量复制,将生成环境的流量复制到测试或预生产环境,这样既能定位实际性能瓶颈,又不影响线上业务。

使用 cProfile 分析和定位 Python 应用性能瓶颈点的更多相关文章

  1. python cProfile分析程序性能

    转自:http://xianglong.me/article/analysis-python-application-performance-using-cProfile/?utm_source=tu ...

  2. IRIS数据集的分析-数据挖掘和python入门-零门槛

    所有内容都在python源码和注释里,可运行! ########################### #说明: # 撰写本文的原因是,笔者在研究博文“http://python.jobbole.co ...

  3. 偶发异常BUG,如何高效精准分析排查定位?

    偶发异常BUG,如何高效精准分析排查定位? 作为测试,经常会收到领导.同事.用户反馈过来各种各样BUG,令人措手不及 首选需要判断确认是不是BUG,不要急于给予回复,需有充分的条件给予说明回复 很多测 ...

  4. uboot2012(一)分析重定位

    目录 引入 环境配置 编译体验 入口查找 代码分析 board_init_f pie 内存分布分析 SP设置 board_init_f 重定位 代码段重定位实现 变量地址修改 参考 title: ub ...

  5. 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 百篇博客分析OpenHarmony源码 | v55.01

    百篇博客系列篇.本篇为: v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程 ...

  6. Java项目性能瓶颈分析及定位(八)——Java线程堆栈分析(五)

    对于CPU而言,常见的瓶颈主要有两种:服务器的压力很小,但是CPU的利用率却很高,这样的性能瓶颈相对比较容易定位(好比我只是说了你一句,你就哭了,你的弱点立马就暴露出来了):给服务器施加的压力很大,但 ...

  7. cProfile分析程序性能

    Python标准库中提供了三种用来分析程序性能的模块,分别是cProfile, profile和hotshot,另外还有一个辅助模块stats.这些模块提供了对Python程序的确定性分析功能,同时也 ...

  8. Android Tombstone/Crash的log分析和定位

    有一句话叫做常在河边走,哪有不湿鞋.我们这些研究和开发Android的project师正应了这句话,相必大家在调试的时候常常会遇到这么个东西吧 *** *** *** *** *** *** *** ...

  9. 一次对象过大引起的gc性能问题的分析与定位

    现象:一个接口在4C的机器上跑最大只有7TPS,CPU使用率就已经90%多. 定位: 1.  使用top命令查看CPU使用情况,找到进程号 2.  使用top -H -pid命令,查看进程信息,看到有 ...

  10. 基于数据形式说明杜兰特的技术特点的分析(含Python实现讲解部分)

    ---恢复内容开始--- 注: 本博文系原创,转载请标明原处. 题外话:春节过后,回到学校无所事事,感觉整个人都生锈一般,没什么动力,姑且称为"春节后遗症".在科赛官网得到关于NB ...

随机推荐

  1. [TK] 一心净士 hzoj-tg-937-2

    万元申万的(不是) 嗯... 另外,这道题其实叫一心净士(shi) 而不是一心净土. 剖析 我们注意到题目要让我们使最小的自然数最大,那么我们的每一个区间都要从零开始放. 显然,假如我们所有区间里最小 ...

  2. [OI] Kruskal 重构树

    算法介绍 Kruskal 重构树用于快速判断节点的连通性. 考虑到,假如两个节点是联通的,则他们之间总会有一条边被选入最小生成树内,因此他们在最小生成树内也是联通的. 也就是说,我们可以通过求最小生成 ...

  3. 林史·CLOI纪事本末

    CLOI正源在JD,JD在初次短期集训结束后带出了一句经典名言: 那如果是在丛林里呢 这句话在短期内在全班范围内流传甚广,因此,\(GreatJungleLord\) 也因其幽默诙谐的形象赢得了大家的 ...

  4. 【问题解决】remote: parse error: Invalid numeric literal at line 1, column 20,解决思路

    问题现象 某同事出现过同样的推送到git仓库报错的问题,报错信息详情如下: Delta compresion using up to 20 threads Compressing objects: 1 ...

  5. 系统 内核启动期间使用ftrace

    启动阶段使能event trace 同上,配置commandline: trace_event=sched:*,timer:*,irq:* trace_buf_size=40M 有上面的实例可以知道, ...

  6. 墨天轮专访TDengine陶建辉:坚持做难而正确的事,三次创业成就不悔人生

    导读: 时序数据库(Time Series Database)在最近几年被越来越多的用户接受并使用,并有广泛的应用场景.云原生时序数据库 TDengine 一直稳居墨天轮时序数据库榜首,其近期的海外发 ...

  7. ByConity与主流开源OLAP引擎(Clickhouse、Doris、Presto)性能对比分析

    引言: 随着数据量和数据复杂性的不断增加,越来越多的企业开始使用OLAP(联机分析处理)引擎来处理大规模数据并提供即时分析结果.在选择OLAP引擎时,性能是一个非常重要的因素. 因此,本文将使用TPC ...

  8. javascript 中 0.1 + 0.2 === 0.3 是否正确 ?

    不正确 ,因为 js 是 动态 .弱类型 ,即时编译的语言 :js中的小数都是浮点型 ,比如 0.1 实际上可能是 0.11111111... 0.2 可能是 0.2 22222..... 所以 0. ...

  9. 不要慌,FastGPT 告诉我这是技术性调整,利好大 A!

    一觉醒来,股市又变天了,到处一片哀嚎,我看了下前几天牛市的赚钱名单,咱们公众号的粉丝没有一个在里面,说实话很失望,希望大家多做些有意义的事情,而不是整天虚度光阴.一个个平时看着都挺厉害,也没赚到钱,我 ...

  10. 云原生周刊:LitmusChaos 审计完成|2024.9.2

    开源项目推荐 Gardener Gardener 实现了 Kubernetes 集群的自动化管理和操作服务,并提供了一个经过完全验证的可扩展性框架,可以调整以适应任何编程云或基础设施提供商. Graf ...