• Python代码优化工具——line_profile


    一、工具介绍

    line_profiler是Python的一个第三方库,其功能时基于函数的逐行代码分析工具。通过该库,可以对目标函数(允许分析多个函数)进行时间消耗分析,便于代码调优。

    二、安装

    使用命令pip install line_profiler进行安装。

    三、分析结果注解

    先放上这个工具的分析结果,各位朋友可以看一下是否满足自己的要求,再决定是否安装以及使用。
    分析结果
    部分参数注解:

    • Total time:当前函数的时间消耗,单位是秒。
    • File:当前函数所在文件名。
    • Function:当前函数的函数名以及在文件中的位置。
    • Line #:代码所在行号。
    • Hits:在执行过程中,该行代码执行次数,即命中数。
    • Time:在执行过程中,该行代码执行的总时间,单位是微秒。
    • Per Hit:在执行过程中,平均每次执行该行代码所耗时间,单位是微秒。
    • % Time:执行该行代码所耗总时间占执行当前函数所耗总时间的百分比。
    • Line Contents:该行代码的内容。

    分析结果保存位置
    待代码执行完毕后,会在当前目录(注意,不是代码所在目录,而是执行命令的当前目录) 下生成一个后缀为.lprof的同名文件,该文件内存放的就是分析结果。

    四、使用

    line_profiler工具有三种使用姿势,各有利弊

    1、使用kernprof命令进行分析

    (1)使用姿势

    在想要分析的函数前加上装饰器@profile,然后在终端数据使用命令kernprof进行分析。该命令的具体参数自行Google,在此不再赘述。

    (2)示例:

    代码如下,该示例共有三个函数,每个函数的功能都是睡眠一段时间后,构造10个随机数。

    import random
    import time
    
    @profile
    def function1():
        time.sleep(2)
        for _ in range(100):
            y = random.randint(1,100)
    
    
    def function2():
        time.sleep(5)
        for _ in range(100):
            y = random.randint(1,100)
    
    
    def function3():
        time.sleep(7)
        for _ in range(100):
            y = random.randint(1,100)
    
    @profile
    def main():
        function1()
        function2()
        function3()
    
    
    if __name__ == "__main__":       
        main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    执行结果如下:
    请添加图片描述
    因为我只在mainfunction1函数加了装饰器,所以分析结果只有mainfunction1,实际使用时可以自行增加或减少函数。

    (3)该姿势的利弊

    优点

    • 不用在代码里导入第三方包,也不用修改代码的实际逻辑,有利于维持原代码的整体性。
    • 使用方便,只需在待分析的函数前加装饰器@profile即可。
    • 用于分析的函数可以不在同一个文件内,方便分析较为复杂、调用方法较多的程序。

    缺点

    • 因为需要在所有待分析的函数前都需要加装饰器,所以添加和删除的麻烦度与待分析的函数的数量成正比。
    • 因为@profile并不是第三方导入的,所以正常运行代码时会报错。
    • 同样是因为@profile不是第三方导入的,在IDEA中该段代码会有代码错误的红色波浪线提示,强迫症震怒。

    2、使用python命令进行分析

    (1)使用姿势

    需要在代码里引入第三方包LineProfiler,并在原代码里添加一些代码才可以实现,进行分析时就像平时执行代码一样python <文件名>即可。

    (2)示例:

    代码如下,该示例共有三个函数,每个函数的功能都是睡眠一段时间后,构造10个随机数。

    import random
    import time
    from line_profiler import LineProfiler
    
    
    def function1():
        time.sleep(2)
        for _ in range(100):
            y = random.randint(1,100)
    
    
    def function2():
        time.sleep(5)
        for _ in range(100):
            y = random.randint(1,100)
    
    
    def function3():
        time.sleep(7)
        for _ in range(100):
            y = random.randint(1,100)
    
    
    def main():
        function1()
        function2()
        function3()
    
    
    if __name__ == "__main__":
        lp = LineProfiler()  # 构造分析对象
        """如果想分析多个函数,可以使用add_function进行添加"""
        lp.add_function(function1)  # 添加第二个待分析函数
        lp.add_function(function2)  # 添加第三个待分析函数
        test_func = lp(main)  # 添加分析主函数,注意这里并不是执行函数,所以传递的是是函数名,没有括号。
        test_func()  # 执行主函数,如果主函数需要参数,则参数在这一步传递,例如test_func(参数1, 参数2...)
        lp.print_stats()  # 打印分析结果
        """
        坑点:
            1:test_func = lp(main)这一步,是实际分析的入口函数(即第一个被调用的函数,但不一定是main函数),所以这里封装的函数必须是测试脚本要执行的第一个函数。
            2:test_func()这一步才是真正执行,如果缺少这一步,代码将不会被执行
            3:lp.print_stats()这一步是打印分析结果,如果缺少这一步,将不会在终端看到分析结果。
            4:分析结果只与是否加入分析队列有关,而不管该函数是否被实际执行,如果该函数加入分析但没有被执行,则Hits、Time等值为空。
        """
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    执行结果如下:
    请添加图片描述

    (3)该姿势的利弊

    优点

    • 添加/删除待分析函数方便,不用修改原代码,只需要在测试代码入口使用LineProfiler对象增加/删除待分析函数名即可。
    • 测试命令与平时运行代码的相同,不用增加学习负担。

    缺点

    • 因为要导入第三方包以及创建LineProfiler对象,需要写一份专用于分析的测试脚本。
    • 分析多个函数时,是使用add_function+函数名来实现的,所以需要显示地导入待分析函数,或者将待分析函数拷贝到当前分析脚本,对较为复杂的逻辑很不友好。
    • 该姿势存在一些坑点,已在示例代码的备注中说明。
    • 不会将分析结果保存到.lprof文件中。

    3、在Jupyter Notebook内使用line_profile

    这一种姿势在实际工作中不常用,感兴趣的可以移步这位大佬的文章:line_profiler: Line by Line Profiling of Python Code

  • 相关阅读:
    【Leetcode】滑动窗口合集
    国际化:i18n
    神经网络模型量化基础
    LeetCode每日一题——1678. 设计 Goal 解析器
    记一次服务宕机、优化全流程(以后也可以装X了)
    Invalid bound statement (not found)异常如何处理呢?
    Java基础—— 反射
    Prettier插件使用
    SpringCloudalibaba2
    如何优雅的使用MyBatis?
  • 原文地址:https://blog.csdn.net/weixin_42245157/article/details/125415104