美文网首页PythonGIT
Python 性能分析大全

Python 性能分析大全

作者: selfboot | 来源:发表于2016-06-13 22:45 被阅读535次

    虽然运行速度慢是 Python 与生俱来的特点,大多数时候我们用 Python 就意味着放弃对性能的追求。但是,就算是用纯 Python 完成同一个任务,老手写出来的代码可能会比菜鸟写的代码块几倍,甚至是几十倍(这里不考虑算法的因素,只考虑语言方面的因素)。很多时候,我们将自己的代码运行缓慢地原因归结于python本来就很慢,从而心安理得地放弃深入探究。

    但是,事实真的是这样吗?面对python代码,你有分析下面这些问题吗:

    • 程序运行的速度如何?
    • 程序运行时间的瓶颈在哪里?
    • 能否稍加改进以提高运行速度呢?

    为了更好了解python程序,我们需要一套工具,能够记录代码运行时间,生成一个性能分析报告,方便彻底了解代码,从而进行针对性的优化(本篇侧重于代码性能分析,不关注如何优化)。

    谁快谁慢

    假设有一个字符串,想将里面的空格替换为字符‘-’,用python实现起来很简单,下面是四种方案:

    def slowest_replace():
        replace_list = []
        for i, char in enumerate(orignal_str):
            c = char if char != " " else "-"
            replace_list.append(c)
        return "".join(replace_list)
    
    def slow_replace():
        replace_str = ""
        for i, char in enumerate(orignal_str):
            c = char if char != " " else "-"
            replace_str += c
        return replace_str
    
    def fast_replace():
        return "-".join(orignal_str.split())
    
    def fastest_replace():
        return orignal_str.replace(" ", "-")
    

    这四种方案的效率如何呢,哪种方案比较慢呢?这是一个问题!

    时间断点

    最直接的想法是在开始 replace 函数之前记录时间,程序结束后再记录时间,计算时间差即为程序运行时间。python提供了模块 time,其中 time.clock() 在Unix/Linux下返回的是CPU时间(浮点数表示的秒数),Win下返回的是以秒为单位的真实时间(Wall-clock time)。

    由于替换函数耗时可能非常短,所以这里考虑分别执行 100000次,然后查看不同函数的效率。我们的性能分析辅助函数如下:

    def _time_analyze_(func):
        from time import clock
        start = clock()
        for i in range(exec_times):
            func()
        finish = clock()
        print "{:<20}{:10.6} s".format(func.__name__ + ":", finish - start)
    

    这样就可以了解上面程序的运行时间情况:

    20160613_vprof_analyze.png

    line_profiler

    上面的测试最多统计到函数的执行时间,很多时候我们想知道函数里面每一行代码的执行效率,这时候就可以用到 line_profiler 了。

    line_profiler 的使用特别简单,在需要监控的函数前面加上 @profile 装饰器。然后用它提供的 kernprof -l -v [source_code.py] 行进行诊断。下面是一个简单的测试程序 line_profile.py:

    from time_profile import slow_replace, slowest_replace
    
    for i in xrange(10000):
        slow_replace()
        slowest_replace()
    

    运行后结果如下:

    输出每列的含义如下:

    • Line #: 行号
    • Hits: 当前行执行的次数.
    • Time: 当前行执行耗费的时间,单位为 "Timer unit:"
    • Per Hit: 平均执行一次耗费的时间.
    • % Time: 当前行执行时间占总时间的比例.
    • Line Contents: 当前行的代码

    line_profiler 执行时间的估计不是特别精确,不过可以用来分析当前函数中哪些行是瓶颈。

    我的博客

    更多阅读

    A guide to analyzing Python performance
    timeit – Time the execution of small bits of Python code
    Profiling Python using cProfile: a concrete case
    profile, cProfile, and pstats – Performance analysis of Python programs.
    How can you profile a Python script?
    检测Python程序执行效率及内存和CPU使用的7种方法
    代码优化概要
    Python性能优化的20条建议

    相关文章

      网友评论

      本文标题:Python 性能分析大全

      本文链接:https://www.haomeiwen.com/subject/slaydttx.html