Python实践58-性能调优之cProfile

cProfile简介

  • cProfile是一个标准库内建的分析工具。它hook进CPython的虚拟机来测量其每一个函数运行所花费的时间。这一技术会引入一个巨大的开销,但你会获得更多的信息。有时这些额外的信息会给你的代码带来令人惊讶的发现。
  • cProfile是标准库内建的三个分析工具之一,另外两个是hotshot和profile。
  • hotshot还处于实验阶段,profile则是原始的纯Python分析器。cProfile具有跟profile一样的接口,且是默认的分析工具。
  • 永远不要忽视靠直觉进行的性能分析(虽然你一定会犯错!)。在分析前先进行假设是绝对值得的,因为这样可以帮助你学习如何定位你代码中可能有问题的地方,而且你应该始终用证据来证明你的选择。

使用cProfile

  • 通过命令行直接profile你的Python程序:python -m cProfile foo.py
  • 输出的字段含义如下:
ncalls:表示函数调用的次数;
tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间;
percall:(第一个percall)等于 tottime/ncalls;
cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;
percall:(第二个percall)即函数运行一次的平均时间,等于 cumtime/ncalls;
filename:lineno(function):每个函数调用的具体信息;

一个例子

  • 定义一个被引用的模块bar
def bar():
    result = 0
    for i in range(1000000):
        result += i
    return result
from bar import bar


def foo():
    result = 0
    for i in range(100000):
        result += i
    for i in range(5):
        bar()
    return result


if __name__ == '__main__':
    foo()
  • 运行cProfile来分析foo.py的性能
python -m cProfile  foo.py
         16 function calls in 0.234 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 bar.py:6(<module>)
        5    0.181    0.036    0.227    0.045 bar.py:6(bar)
        1    0.000    0.000    0.234    0.234 foo.py:5(<module>)
        1    0.003    0.003    0.233    0.233 foo.py:8(foo)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        7    0.049    0.007    0.049    0.007 {range}
  • 从profile结果可以看出父函数foo自己占用的CPU时间并不多,大部分的CPU时间都被子函数bar给占用了。

代码地址

本系列文章和代码已经作为项目归档到github,仓库地址:jumper2014/PyCodeComplete。大家觉得有帮助就请在github上star一下,你的支持是我更新的动力。什么?你没有github账号?学习Python怎么可以没有github账号呢,快去注册一个啦!