一、需求背景

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

二、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. Spring —— bean生命周期

    bean生命周期 生命周期:从创建到消亡的完整过程 bean生命周期:bean从创建到销毁的整体过程 bean生命周期控制:在bean创建后到销毁前做一些事情   方式一:配置控制生命周期 <b ...

  2. Nuxt Kit 中的模板处理

    title: Nuxt Kit 中的模板处理 date: 2024/9/20 updated: 2024/9/20 author: cmdragon excerpt: 摘要:本文详细介绍了在Nuxt ...

  3. cortex-m3 m4 异常机制

    文章写的很好,待整理 1.[STM32]HardFault问题详细分析及调试笔记 https://blog.csdn.net/m0_54916619/article/details/129979222 ...

  4. kaggle入门 随机森林求解Titanic

    # kaggle Titanic # 导入需要的库 import pandas as pd import numpy as np import sys import sklearn import ra ...

  5. [OI] 偏序

    \(n\) 维偏序即给出若干个点对 \((a_{i},b_{i},\cdots,n_{i})\),对每个 \(i\) 求出满足 \(a_{j}\gt a_{i},b_{j}\gt b_{i}\cdot ...

  6. SuperMap iPortal对接流数据方案

    本文结合文章<SuperMap流数据应用技术方案>,使用SuperMap iPortal实时流数据接入数据上图APP中 iPortal软件下载地址(本文使用10.0.1 win64位): ...

  7. 15. 序列化模块json和pickle、os模块

    1. 序列化模块 1.1 序列化与反序列化 (1)序列化 将原本的python数据类型字典.列表.元组 转换成json格式字符串的过程就叫序列化 (2)反序列化 将json格式字符串转换成python ...

  8. dotnet Core 静态方法和构造方法

    // 静态方法: // 特点:1.生命周期一旦创建-应用结束 才会结束 2.全局的 3.效率高(放在内存中) // 用户:用户登录,系统配置信息,系统设置,SQLHelper // 注意:静态的东西创 ...

  9. 9.24 csp(没学会的网络流)

    T1.商品 因为边界 l , r 是线性移动的,所以答案可以线性改变,直接用set维护连续段(小于l的和大于r的)的个数,并维护ans即可. 因为set的一个小错误调了两个小时,代码打成了一坨,结果最 ...

  10. 自建家庭 KTV,在家想嗨就嗨

    现在用户最多.曲库最多的 K 歌软件是全民K歌,基本上想唱的歌都有,而且基本上每首歌都有 MV 或视频,使用体验也还不错,但是收费太贵了,对于一个月唱不了几次的打工人来说,唱一首歌就是"天价 ...