python——profile、line_profiler和memory_profiler模塊

profile和line_profiler兩個模塊都是性能分析工具。有時候需要找到代碼中運行速度較慢處或瓶頸,可以通過這兩模塊實現,而不再使用time計時。

line_profiler模塊可以記錄每行代碼的運行時間和耗時百分比。

memory_profiler模塊用來監控進程,記錄每行代碼的內存使用狀況。

profile是python自帶性能分析模塊。line_profiler和memory_profiler模塊都需要自行安裝。

profile

常用方法
profile.run(statement, filename=None, sort=-1)
#filename用來設置輸出文件,默認直接打印

輸出結果的各項含義:

名稱 含義
ncalls 函數被調用次數
tottime 函數(除去子函數)總運行時間
percall 平均時間,等於tottime/ncalls
cumtime 函數(包括子函數)總運行時間
percall 平均時間,等於cumtime/ncalls
filename 文件:行號(函數)

基於上述信息可以分析代碼性能,通過filename可以知道哪個文件第幾行的啥函數運行了多少次,運行時間多少。

示例
import profile
a=[[1,5],[2,3],[6,6],[0,0]]
profile.run('sorted(a,key=lambda x:x[1])')
'''
 9 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 :0(exec)
        1    0.000    0.000    0.000    0.000 :0(setprofile)
        1    0.000    0.000    0.000    0.000 :0(sorted)
        4    0.000    0.000    0.000    0.000 <string>:1(<lambda>)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.000    0.000 profile:0(sorted(a,key=lambda x:x[1]))
'''
#通過上述結果,可以看出string中第1行的lambda函數運行了四次

也可以先生成Profiler實例對象,再run:

p=profile.Profile()
p.run('sum')      #<profile.Profile at 0x7f01ca552c18>
p.print_stats()   #將性能打印出來

line_profiler

常用方法

該模塊常通過裝飾器來使用。在安裝好該模塊後,編寫需要測試的python程序,並在需要測試的函數上方加入@profile,保存爲*.py文件。在命令行使用kernprof -l -v *.py,在輸出打印出程序結果之後會打印性能分析。

輸出結果的含義:

名稱 意義
Timer unit 計時器單位,微秒
Total time 測試代碼總運行時間
File 測試代碼文件名
Hits 每行代碼運行次數
Time 每行代碼運行時間
Per Hit 每行代碼運行一次的時間
% Time 每行代碼運行時間的百分比
Line Contents 每行代碼
示例

將下列代碼保存爲test.py,不需要導入line_profiler模塊。

@profile
def compute():
    for i in range(100):
        print(i**3)
if __name__=='__main__':
    compute()

在命令行運行kernprof -l -v test.py,注意如果test.py不在命令行當前文件夾,需要些寫上路徑。輸出爲:

'''
Wrote profile results to test.py.lprof
Timer unit: 1e-06 s

Total time: 0.012405 s
File: test.py
Function: compute at line 1

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     1                                           @profile
     2                                           def compute():
     3       101         74.0      0.7      0.6      for i in range(100):
     4       100      12331.0    123.3     99.4          print(i**3)
'''
#可以分析代碼性能,比如 print(i**3)共執行了100次,平均每次運行時間123.3微秒。

memory_profiler

常用方法

使用方法同line_profiler模塊,藉助裝飾器調用。在需要分析的函數上方加@profile。在命令行使用python -m memory_profiler *.py運行代碼。
輸出結果中:
Mem usage:內存使用情況
Increment:每行代碼運行後內存增減情況

還有一種調用該模塊的方式,在測試代碼中導入memory_profiler模塊的profile方法,如下:

from memory_profiler import profile

其餘編寫方法同上,裝飾器的參數如下:

@profile(func=None, stream=None, precision=1, backend='psutil')
#stream表示將分析結果輸出的文件,默認爲命令行;precision表示分析結果中數字小數點保留位數。

這種方法在命令行只需運行python *.py即可,若不需要測試性能,可直接將裝飾器註釋掉。

示例

將下列代碼保存爲test.py,不需要導入line_profiler模塊。

from memory_profiler import profile
@profile(precision=2)
def compute():
    a=[]
    b=3.4
    for i in range(10):
        a.append(i)
    del b
if __name__=='__main__':
    compute()

在命令行運行python test.py,注意路徑。若代碼中沒有導入memory_profiler模塊的profile方法,則應該運行python -m memory_profiler test.py。輸出爲:

'''
Line #    Mem usage    Increment   Line Contents
================================================
     2    39.08 MiB    39.08 MiB   @profile(precision=2)
     3                             def compute():
     4    39.08 MiB     0.00 MiB       a=[10]*100
     5    39.08 MiB     0.00 MiB       b=3.4
     6    39.08 MiB     0.00 MiB       for i in range(10):
     7    39.08 MiB     0.00 MiB           a.append(i)
     8    39.08 MiB     0.00 MiB       del b
'''
#輸出分析結果的數字保留了2位小數
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章