Python使用cProfile分析和定位應(yīng)用性能瓶頸點(diǎn)
一、需求背景
性能壓測(cè)時(shí),發(fā)現(xiàn)某接口存在性能瓶頸,期望借助工具定位該瓶頸,最好能定位至具體慢方法。
二、cProfile 簡(jiǎn)介
cProfile 是 Python 標(biāo)準(zhǔn)庫(kù)中的一個(gè)模塊,用于對(duì) Python 程序進(jìn)行性能分析,它能輸出每個(gè)函數(shù)的調(diào)用次數(shù)、執(zhí)行耗時(shí)等詳細(xì)信息,可幫助開(kāi)發(fā)者識(shí)別程序中運(yùn)行緩慢的方法,以便進(jìn)行性能優(yōu)化,適合作為上述需求的解決方案。
此外,Python 還內(nèi)置了使用純 Python 實(shí)現(xiàn)的 profile 模塊,與 cProfile 功能一樣,只不過(guò) cProfile 是用 C 語(yǔ)言編寫,性能更高、開(kāi)銷更小,適合在性能敏感的環(huán)境(如線上生產(chǎn)環(huán)境)中使用。profile 是純 Python 實(shí)現(xiàn)的模塊,性能開(kāi)銷相對(duì)較大,但因其用 Python 編寫,易于理解和修改,適合學(xué)習(xí)時(shí)使用。
三、使用方法
cProfile 支持三種使用方法,一是硬編碼于代碼中;二是在 Python 應(yīng)用啟動(dòng)時(shí)加載 cProfile 模塊;三是通過(guò) IDE(PyCharm)運(yùn)行。開(kāi)發(fā)環(huán)境建議采用方法三,因其簡(jiǎn)單易用且結(jié)果圖表豐富;生產(chǎn)環(huán)境建議采用方法二,此方法對(duì)代碼無(wú)侵入性。
1. 硬編碼于代碼中
示例代碼:
import cProfile def my_function(): # Some code to profile pass profiler = cProfile.Profile() profiler.enable() my_function() profiler.disable() profiler.print_stats()
執(zhí)行結(jié)果:
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}
結(jié)果字段說(shuō)明:
ncalls:函數(shù)調(diào)用的次數(shù)。
tottime:在該函數(shù)中花費(fèi)的總時(shí)間,不包括調(diào)用子函數(shù)的時(shí)間。
percall:tottime 除以 ncalls。
cumtime:該函數(shù)及其所有子函數(shù)中花費(fèi)的總時(shí)間。
percall:cumtime 除以原始調(diào)用次數(shù)。
filename:lineno(function):函數(shù)所在的文件名、行號(hào)和函數(shù)名。
2. 在 Python 應(yīng)用啟動(dòng)時(shí)加載 cProfile 模塊
示例代碼:
python -m cProfile my_script.py # 方法一、將結(jié)果輸出至控制臺(tái) python -m cProfile -o output.prof my_script.py # 方法二、將結(jié)果保存到指定的prof文件
可使用 snakeviz 插件(安裝方法為pip install snakeviz
)分析 prof 文件。執(zhí)行snakeviz output.prof
后,會(huì)將結(jié)果掛載到 web 容器中,支持通過(guò) URL(如http://127.0.0.1:8080/snakeviz/xxxoutput.prof
)訪問(wèn)。
3. 通過(guò) IDE(PyCharm)運(yùn)行
使用方法:
通過(guò)菜單 [run] > [profile 'app'](其中 app 為應(yīng)用名稱,下同)啟動(dòng)應(yīng)用。待應(yīng)用執(zhí)行完畢且停止后,相關(guān)面板會(huì)輸出相應(yīng)的調(diào)用統(tǒng)計(jì)與調(diào)用鏈。
調(diào)用統(tǒng)計(jì):
表頭“Name”表示被調(diào)用的模塊或函數(shù);“Call Count”表示被調(diào)用次數(shù);“Time (ms)”表示耗時(shí)及百分比,時(shí)間單位為毫秒。
點(diǎn)擊表頭列名可對(duì)該列進(jìn)行排序。
在調(diào)用統(tǒng)計(jì)中,選擇“name”列的單元格,右鍵選中“Navigate to Source”或“Show on Call Graph”,可打開(kāi)其源碼或?qū)?yīng)的調(diào)用鏈及位置。
調(diào)用鏈:
此外,通過(guò)菜單 [run] > [Concurrency Diagram 'app'] 啟動(dòng)程序,可查看到線程和異步協(xié)程(Asyncio)的調(diào)用情況,如下圖所示:
四、相關(guān)配置項(xiàng)
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> # 將分析結(jié)果輸出到指定的文件中。 -s SORT, --sort=SORT Sort order when printing to stdout, based on pstats.Stats class # 指定輸出結(jié)果的排序方式??梢愿鶕?jù)不同的字段進(jìn)行排序,如 time, cumulative, calls 等。 -m Profile a library module # 分析一個(gè)模塊,而不是一個(gè)腳本文件
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) # 用于指定綁定的主機(jī)名,默認(rèn)值為 127.0.0.1,即本地主機(jī)。 -p PORT, --port PORT port to bind to; if this port is already in use a free port will be selected automatically (default: 8080) # 用于指定綁定的端口。如果指定的端口已被占用,程序?qū)⒆詣?dòng)選擇一個(gè)空閑端口。默認(rèn)值為 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 模塊的文檔描述,指定要啟動(dòng)的瀏覽器名稱。用戶可以通過(guò)指定瀏覽器的路徑來(lái)控制使用哪個(gè)瀏覽器打開(kāi)應(yīng)用。 -s, --server start SnakeViz in server-only mode--no attempt will be made to open a browser # 僅在服務(wù)器模式下啟動(dòng) SnakeViz,不會(huì)嘗試打開(kāi)服務(wù)器中的瀏覽器。對(duì)于非圖形化或不帶瀏覽器的服務(wù)器非常有用。
五、生產(chǎn)環(huán)境使用示例
生產(chǎn)環(huán)境系統(tǒng)版本為 CentOS 7.9.2009 (Core),內(nèi)核為 5.15.81,使用 4 核 4G 的容器運(yùn)行DB-GPT controller 子系統(tǒng)。
1. 使用步驟
(1)執(zhí)行腳本:/usr/local/bin/python3.10 -m cProfile -o out.prof /usr/local/bin/dbgpt start controller &
,在 Python 應(yīng)用啟動(dòng)時(shí)加載 cProfile 模塊。
(2)執(zhí)行相關(guān)接口壓測(cè)。
(3)正常停止應(yīng)用,生成性能分析結(jié)果文件(out.prof)。注意:性能分析結(jié)果只能是在程序正常停止后才能輸出。常規(guī)兩種做法:其一、后臺(tái)守護(hù)進(jìn)程,可以使用 kill -2 {應(yīng)用 PID}
;其二、前臺(tái)進(jìn)程,通過(guò) Ctrl + C 退出。
(4)使用snakeviz -H 0.0.0.0 -s out.prof
分析結(jié)果文件(其中 -s 僅在服務(wù)端模式下運(yùn)行,不會(huì)嘗試打開(kāi)服務(wù)器瀏覽器,一般情況下服務(wù)器不自帶瀏覽器;-H 0.0.0.0,支持監(jiān)聽(tīng)網(wǎng)卡所有接口),執(zhí)行成功后,會(huì)輸出可訪問(wèn)的 URL 地址,通過(guò)外部或本地瀏覽器打開(kāi)。
2. 結(jié)果分析
使用外部或本地瀏覽器訪問(wèn) snakeviz 生成的 URL 地址。結(jié)果如下:
結(jié)果說(shuō)明:
(1)結(jié)果包含兩部分,即上圖和下表。上圖展示選中方法及其子方法的調(diào)用關(guān)系、耗時(shí)及占比;下表展示所有方法及其總調(diào)用次數(shù)(ncalls)、方法本身總耗時(shí)(tottime)、方法本身平均耗時(shí)(percall)、方法及其子方法總耗時(shí)(cumtime)、方法及其子方法平均耗時(shí)(percall)以及方法所在文件位置及其行列號(hào)。
使用說(shuō)明:
(1)表格任意列支持升降序操作,選中任意行,頁(yè)面上方的圖形會(huì)自動(dòng)展示該方法及其子方法的調(diào)用關(guān)系、耗時(shí)及占比。
(2)單擊圖形中的任意子模塊,可查看子模塊所在方法及其子方法的調(diào)用關(guān)系、耗時(shí)及占比。
分析建議:
(1)選擇 cumtime 列降序,選擇入口代碼,逐步細(xì)看,分析瓶頸點(diǎn)。
(2)使用 Sunburst 圖樣展示,更易體現(xiàn)各方法耗時(shí)占比。
3. 評(píng)估加載 cProfile 對(duì)性能的影響
我們用 Jmeter 對(duì)未加載以及加載 cProfile 模塊的 Python 應(yīng)用性能進(jìn)行評(píng)估,以判斷生產(chǎn)環(huán)境加載 cProfile 對(duì)性能的影響程度。結(jié)果如下:
配置 | Jmeter 壓測(cè)線程數(shù) | CPU 使用率 | 吞吐量 | 平均響應(yīng)時(shí)間 |
---|---|---|---|---|
CASE1 某應(yīng)用未加載 cProfile | 20 | 接近單核 100% | 527 | 36ms |
CASE2 某應(yīng)用加載 cProfile 后 | 20 | 接近單核 100% | 395 | 49ms |
從上表可知,加載 cProfile 后,應(yīng)用吞吐量下降 25%,平均響應(yīng)時(shí)間增加 13ms,對(duì)性能有一定影響。
五、遇到問(wèn)題
kill -15 {應(yīng)用 PID} 無(wú)法生成性能分析結(jié)果文件
由于 cProfile 僅支持監(jiān)聽(tīng)中斷(SIGINT)信號(hào),導(dǎo)致 kill 15 發(fā)送 SIGTERM 信號(hào)時(shí),無(wú)法生成性能分析結(jié)果文件。
解決辦法:使用 kill -2 {應(yīng)用 PID}。
六、使用總結(jié)
(1)cProfile 可以生成詳細(xì)的性能分布和調(diào)用鏈,非常適合作為分析和定位 Python 應(yīng)用性能瓶頸的工具。
(2)由于生成性能分析結(jié)果文件需要停止應(yīng)用,且對(duì)性能損耗較大(吞吐量降低 25%),所以一般情況下不建議在生產(chǎn)環(huán)境直接使用。不過(guò)可以使用流量復(fù)制,將生成環(huán)境的流量復(fù)制到測(cè)試或預(yù)生產(chǎn)環(huán)境,這樣既能定位實(shí)際性能瓶頸,又不影響線上業(yè)務(wù)。
到此這篇關(guān)于Python使用cProfile分析和定位應(yīng)用性能瓶頸點(diǎn)的文章就介紹到這了,更多相關(guān)Python cProfile內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Pandas中Series和DataFrame的索引實(shí)現(xiàn)
這篇文章主要介紹了Pandas中Series和DataFrame的索引實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Django框架 查詢Extra功能實(shí)現(xiàn)解析
這篇文章主要介紹了Django框架 查詢Extra功能實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09python3+django2開(kāi)發(fā)一個(gè)簡(jiǎn)單的人員管理系統(tǒng)過(guò)程詳解
這篇文章主要介紹了python3+django2開(kāi)發(fā)一個(gè)簡(jiǎn)單的人員管理系統(tǒng)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07使用Python制作一個(gè)數(shù)據(jù)預(yù)處理小工具(多種操作一鍵完成)
這篇文章主要介紹了使用Python制作一個(gè)數(shù)據(jù)預(yù)處理小工具(多種操作一鍵完成),本文通過(guò)圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02python pip安裝包出現(xiàn):Failed building wheel for xxx錯(cuò)誤的解決
今天小編就為大家分享一篇python pip安裝包出現(xiàn):Failed building wheel for xxx錯(cuò)誤的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12