文章目錄
- 引言
- 1. cProfile:最便捷的性能分析
- 保存性能資料
- 查看性能資料
- 查看耗時最多的子函式
- 查看特定名稱函式的耗時
- 2. timeit:計算小代碼片段的耗時
- 3. IDE中的性能分析
- 小結
引言
如果你想優化python程式的運行效率,你會從哪里下手?
首先,我們要找到「性能瓶頸」,比如哪些函式的運行效率低、計算時間長,然后分析原因,針對性地進行優化,
最樸素的方法是,在你預估的函式前后加上time.perf_counter()1,然后得出這個函式的運行時間,但這種方法不適用于具有大量函式呼叫的程式,
import time
start = time.perf_counter()
func()
print("cost %s second" % (time.perf_counter() - start))
python有很多性能分析工具,功能強大,可以幫助我們對各種函式的性能進行分析,
這篇文章就介紹三種簡單的性能分析工具,其中cProfile和timeit都是python標準庫中的工具,無需安裝第三方庫,看完本篇文章,教你快速上手,
1. cProfile:最便捷的性能分析
推薦指數: ????????
cProfile是python標準庫中一個使用便捷、開銷合理的 C 擴展,適用于分析長時間運行的程式,2
不想閱讀太多細節的小伙伴,可以直接看代碼,非常簡單,直接在cProfile.run中輸入目標函式名稱:
import cProfile
import test_module
cProfile.run('test_module.func()')
在程式運行完后,就會在控制臺列印test_module.func()運行的具體耗時情況:
538569 function calls (519249 primitive calls) in 71.446 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
44 0.002 0.000 0.197 0.004 ImageFile.py:154(load)
18 0.000 0.000 0.001 0.000 ImageFile.py:278(load_prepare)
1 0.000 0.000 0.000 0.000 ImageFile.py:30(<module>)
1 0.000 0.000 0.000 0.000 ImageFile.py:313(StubImageFile)
1 0.000 0.000 0.000 0.000 ImageFile.py:339(Parser)
13 0.001 0.000 1.348 0.104 ImageFile.py:478(_save)
每一行依次列出了各個子函式的運行分析資訊:
-
ncalls
呼叫次數 -
tottime
在給定函式中花費的總時間(不包括呼叫子函式的時間) -
percall
tottime除以ncalls的商 -
cumtime
是在這個函式和所有子函式中花費的累積時間(從呼叫到退出), -
percall
是cumtime除以原始呼叫次數的商 -
filename:lineno(function)
提供每個函式的各自資訊
保存性能資料
如果你想保存這些性能資料,在run函式的引數中加上’restats’檔案名:
cProfile.run('main()','restats')
就會保存到當前目錄下的restats檔案中,
查看性能資料
加載這些資料,可以進行后續的比較分析,
import pstats
from pstats import SortKey
# 加載保存到restats檔案中的性能資料
p = pstats.Stats('restats')
# 列印所有統計資訊
p.strip_dirs().sort_stats(-1).print_stats()
查看耗時最多的子函式
最常用的是,查看耗時最多的函式排序,比如前十個:
# 列印累計耗時最多的10個函式
p.sort_stats(SortKey.CUMULATIVE).print_stats(10)
# 列印內部耗時最多的10個函式(不包含子函式)
p.sort_stats(SortKey.TIME).print_stats(10)

上面兩個例子分別用到用SortKey.CUMULATIVE或SortKey.TIME引數,
SortKey的具體引數如下表所示3:

查看特定名稱函式的耗時
例如,我們在耗時排序中,發現一些加載函式的耗時較大,可以單獨統計下包含load的呼叫資訊:
# 列印包含load的函式名的呼叫者統計資訊
p.print_callers(.5, 'load')
0.5表示串列被剔除到其原始大小的50%,然后保留包含load的行:

例如,還可以查看哪些類的初始化__init__函式耗時較多:
# 按耗時排序,依次列印類的__init__方法的統計資訊
p.sort_stats(SortKey.CUMULATIVE).print_stats('__init__')

2. timeit:計算小代碼片段的耗時
推薦指數: ????
timeit適用于測量小段代碼的耗時,可以在python代碼中呼叫,也可以在命令列中呼叫4,timeit的設計避免了許多用于測量執行時間的常見陷阱,
測驗你寫的函式的運行時間:
def test():
"""Stupid test function"""
L = [i for i in range(100)]
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
測驗一個陳述句的運行時間:
$ python -m timeit 'if hasattr(str, "__bool__"): pass'
50000 loops, best of 5: 4.26 usec per loop
使用方式:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]
-
-n N, --number=N
執行“陳述句”多少次 -
-r N, --repeat=N
重復計時器多少次(默認 5) -
-s S, --setup=S
最初執行一次的陳述句(默認pass) -
-p, --process
測量行程時間,而不是掛鐘時間,使用time.process_time() 代替time.perf_counter(),這是默認值
3.3 版中的新功能, -
-u, --unit=U
指定定時器輸出的時間單位;可以選擇 nsec、usec、msec 或 sec
3.5 版中的新功能, -
-v, --verbose
列印原始計時結果;重復以獲得更多數字精度 -
-h, --help
列印一個簡短的使用資訊并退出
3. IDE中的性能分析
推薦指數: ??????
如果你有IDE,那么很多IDE都提供了性能分析的相關工具,
以pycharm 專業版為例,從Run中點擊Profile,即可對當前python腳本進行性能分析,

程式運行結束后,pycharm會生成以下統計:

這里列出了子函式的名稱、呼叫次數、耗時等資訊,雙擊函式名可以查看對應原始碼,
小結
本文整理了三個常用的python性能分析工具,幫助你定位python程式的性能瓶頸,
如果對你有所幫助,歡迎一鍵三連,支持下博主,
https://docs.python.org/3/library/time.html#time.perf_counter ??
https://docs.python.org/3/library/profile.html ??
https://docs.python.org/3/library/profile.html#module-pstats ??
https://docs.python.org/3/library/timeit.html ??
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/298669.html
標籤:python
