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位小数
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章