Python 性能分析工具 cProfile - 图1

time cmd

一般看看 py 脚本的性能, 可以使用古老的 linux 工具 time, 或者自己在代码中写上 time.clock().

  1. codewars time python3 xingneng.py
  2. python3 xingneng.py 4.64s user 0.02s system 99% cpu 4.698 total

这样粒度比较粗超, 进一步的分析可以借助标准库中的三个分析模块: cProfile profile hotshot.

python3中, hotshot已经被废弃了, 如果没有特殊需求, 建议使用 cProfile. 本文简单介绍下使用 gprof2dotcProfile 分析 python 脚本性能.

cProfile

1. cProfile 和 profile

cProfileprofile 的用法基本相同, 一个是 C 实现的模块, 一个是 Python 实现的模块.

推荐使用 cProfile, 因为profile 分析很慢, 开销很多~

具体用法有代码中使用以及命令行使用, 如下:

代码中使用

  1. import cProfile
  2. cProfile.run('test()')
  3. import profile
  4. profile.run('test()')

Terminal 中使用

测试代码如下, 跑斐波那契数列:

  1. fib = lambda n: 1 if n <= 2 else fib(n - 1) + fib(n - 2)
  2. def test1():
  3. fib(20)
  4. def test2():
  5. fib(30)
  6. def test3():
  7. fib(35)
  8. if __name__ == '__main__':
  9. test1()
  10. test2()
  11. test3()

使用方式如下:

  1. codewars python3 -m cProfile xingneng.py
  2. 20132541 function calls (7 primitive calls) in 5.947 seconds
  3. Ordered by: standard name
  4. ncalls tottime percall cumtime percall filename:lineno(function)
  5. 20132537/3 5.947 0.000 5.947 1.982 xingneng.py:1(<lambda>)
  6. 1 0.000 0.000 5.947 5.947 xingneng.py:1(<module>)
  7. 1 0.000 0.000 5.947 5.947 xingneng.py:4(test)
  8. 1 0.000 0.000 5.947 5.947 {built-in method builtins.exec}
  9. 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
  1. codewars python3 -m profile xingneng.py
  2. 20132544 function calls (10 primitive calls) in 46.235 seconds
  3. Ordered by: standard name
  4. ncalls tottime percall cumtime percall filename:lineno(function)
  5. 1 0.000 0.000 46.234 46.234 :0(exec)
  6. 1 0.001 0.001 0.001 0.001 :0(setprofile)
  7. 1 0.000 0.000 46.235 46.235 profile:0(<code object <module> at 0x106e87810, file "xingneng.py", line 1>)
  8. 0 0.000 0.000 profile:0(profiler)
  9. 20132537/3 46.234 0.000 46.234 15.411 xingneng.py:1(<lambda>)
  10. 1 0.000 0.000 46.234 46.234 xingneng.py:1(<module>)
  11. 1 0.000 0.000 42.455 42.455 xingneng.py:12(test3)
  12. 1 0.000 0.000 0.033 0.033 xingneng.py:4(test1)
  13. 1 0.000 0.000 3.746 3.746 xingneng.py:8(test2)

可以看到每个函数的具体消耗时间. 此处有个问题, 为毛使用 profile 会这么慢?

2. 图形化展示

调优自己的代码可以在 log 中打印分析结果, 不过还是图像比较直观, 可以借助 gprof2dot, 可以看到调用次数, 占用时间和百分比, 简直6到家了~

2.1 安装

  • Mac
  1. brew install gprof2dot
  • Debian/Ubuntu users
  1. apt-get install python graphviz

2.2 使用

比如我将 cProfile 执行后的性能分析文件, 渲染成图片:

  1. codewars python3 -m cProfile -o output.pstat xingneng.py
  2. codewars gprof2dot -f pstats output.pstat | dot -Tpng -o output.png

结果如下:

Python 性能分析工具 cProfile - 图2

其他好玩的绘图用法请看文档

参考文档

  1. A guide to analyzing Python performance
  2. gprof2dot