1. 性能调优
在代码可以实现功能且健壮不出错的前提下,我们往往会有优化性能的需求
性能调优大约可以在运行时间和运行内存占用两方面来考量,下面介绍的工具定位精度由粗到细,也分为这两个方面
1.1. 测试整体运行时间
Python中的timeit是测试代码执行效率的工具.可以用命令行直接测试脚本,也可以测试代码字符串的效率,当然最简单的还是直接用ipython的内置timeit魔法命令测某段代码的效率
import timeit t = timeit.Timer('map(lambda x: x**2,range(1000))') t.timeit() 0.404256040987093 !python -m timeit -s "map(lambda x: x**2,range(1000))" 100000000 loops, best of 3: 0.00833 usec per loop 1.2. 函数级性能瓶颈定位
python的标准库中有一个可以实现性能瓶颈定位的模块叫cprofile,他是一个开销极小的C扩展.用它可以实现函数级的性能分析,配合pstats模块还可以输出分析报告
1.2.1. 使用单独模块分析
%%writefile src/C3/profile_test.py def foo(): sum = 0 for i in range(10000): sum += i return sum if __name__=="__main__": foo() Overwriting src/C3/profile_test.py %%writefile src/C3/profile_test.py def foo(): sum = 0 for i in range(10000): sum += i return sum if __name__=="__main__": try : import profile except: import cProfile as profile profile.run("foo()") Overwriting src/C3/profile_test.py !python src/C3/profile_test.py 5 function calls in 0.002 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.001 0.001 :0(exec) 1 0.001 0.001 0.001 0.001 :0(setprofile) 1 0.000 0.000 0.001 0.001 <string>:1(<module>) 1 0.000 0.000 0.002 0.002 profile:0(foo()) 0 0.000 0.000 profile:0(profiler) 1 0.001 0.001 0.001 0.001 profile_test.py:1(foo) 1.2.2. 使用命令行分析
0.404256040987093 0 0.404256040987093 10.404256040987093 2 0.404256040987093 31.2.3. 统计项说明
| 统计项 | 说明 |
|---|---|
| ncalls | 函数被调用次数 |
| tottime | 函数总计运行时间,不含调用函数运行时间 |
| cumtime | 函数总计运行时间,含调用的函数运行时间 |
| percall | 函数运行一次平均时间,等于tottime(cumtime)/ncalls |
filename:lineno | 函数所在文件名,函数的行号,函数名 |
1.2.4. 与pstats结合提供多种形式的报表
0.404256040987093 4 0.404256040987093 50.404256040987093 6 0.404256040987093 7stats有许多函数,可以提供不同的报表
- stats函数说明
| 函数 | 说明 |
|---|---|
| strip_dirs() | 除去文件名前名的路径信息 |
| add(filename,[...]) | 把profile输出的文件加入stats实例中统计 |
| dump_stats(filename) | 把stats统计结果保存到文件 |
| sort_stats(key,[...]) | 最重要的,可以给profile统计结果排序 |
| reverse_order() | 数据反排序 |
| print_stats([restriction,...]) | 把报表输出到stdout |
| print_callers([restriction,...]) | 输出调用指定函数的相关信息 |
| print_callees([restriction,...]) | 输出指定函数调用过的函数的相关信息 |
- sort_stats可接受的参数
| 参数 | 说明 |
|---|---|
| ncalls | 被调次数 |
| cumulative | 函数运行总时间 |
| file | 文件名 |
| module | 模块名 |
| pcalls | 简单统计 |
| line | 行号 |
| name | 函数名 |
| nfl | name,file,line |
| stdname | 标准函数名 |
| time | 函数内部运行时间 |
1.3. 语句级性能瓶颈定位
cprofiler只能追踪到哪个函数是性能瓶颈,而函数中哪条语句是性能瓶颈就追踪不到了,对于语句级性能瓶颈定位,python并没有官方工具,但github上有位大神制作了line_profiler,这个工具可以实现这一功能,它也几乎可以说是python的半标准工具之一了.
因为不是标准库中的内容,所以需要pip安装.
使用方法十分简单,在需要分析的函数上面加上装饰器@profile即可(注意不用import任何东西,这条装饰器在定位好后应该删除以保证代码可以运行)
0.404256040987093 8 0.404256040987093 9!python -m timeit -s "map(lambda x: x**2,range(1000))" 0 !python -m timeit -s "map(lambda x: x**2,range(1000))" 11.4. 内存分析
memory_profiler是用来分析内存使用情况和追踪内存泄露的工具.它用法比较接近line_profiler
由于不是标准库中的模块,它需要pip安装.
需要注意的是windows下需要在script文件夹下将mprof文件改名为mprof.py并在同一目录下创建一个mprof.bat文件编辑为如下内容
!python -m timeit -s "map(lambda x: x**2,range(1000))" 2 它的使用及其简单:
!python -m timeit -s "map(lambda x: x**2,range(1000))" 3 !python -m timeit -s "map(lambda x: x**2,range(1000))" 4之后使用
!python -m timeit -s "map(lambda x: x**2,range(1000))" 5 就可以看到详细结果了
指定精度可以在profile装饰器后面加上参数 如: @profile(precision=4)
mprof工具类似kernprof,用它可以输出更加友好的统计分析页面
!python -m timeit -s "map(lambda x: x**2,range(1000))" 6 !python -m timeit -s "map(lambda x: x**2,range(1000))" 7!python -m timeit -s "map(lambda x: x**2,range(1000))" 8 !python -m timeit -s "map(lambda x: x**2,range(1000))" 9100000000 loops, best of 3: 0.00833 usec per loop 0 100000000 loops, best of 3: 0.00833 usec per loop 11.5. 对象分析及追踪(windows下不能用)
Objgraph可以实现对象分析和追踪,它也是用pip安装,不过它依赖xdot(pip 安装) 和graphviz(brew安装)
它可以实现的功能有:
- 统计
- 定义过滤对象
- 遍历和显示对象图
100000000 loops, best of 3: 0.00833 usec per loop 2 100000000 loops, best of 3: 0.00833 usec per loop 3100000000 loops, best of 3: 0.00833 usec per loop 4 100000000 loops, best of 3: 0.00833 usec per loop 5于是你可以看到图了






还没有评论,来说两句吧...