• Python中计算程序的运行时间——timeit模块


    绪论

    time.time()方法time.clock()方法可以用来计算程序执行时间及cpu时间。但是,很多时候我们只想对某些代码片段或者算法进行执行时间的统计,这时候,使用timeit模块就比较方便。

    timeit 模块是 Python 标准库中的模块,无需安装,直接导入就可以使用。timeit模块是Python内置的用于统计小段代码执行时间的模块,它同时提供命令行调用接口。

    导入时直接 import timeit ,可以使用 timeit() 函数repeat() 函数,还有 Timer 类。使用 from timeit import … 时,只能导入 Timer 类(有全局变量 all 限制)。

    一、timeit的基本用法

    1.1 timeit.timeit()函数: 创建一个Timer实例,并运行代码进行计时,默认将代码执行一百万次。

    基本语法:

    timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
    

    参数说明:

    • stmt:传入需要测试时间的代码,可以直接传入代码表达式或单个变量,也可以传入函数。传入函数时要在函数名后面加上小括号,让函数执行,如 stmt = ‘func()’ 。
    • setup:传入 stmt 的运行环境,如 stmt 中使用到的参数、变量,要导入的模块等,如 setup = ‘from __main__ import func' (__main__表示当前的文件)。可以写一行语句,也可以写多行语句,写多行语句时用分号隔开。。
    • timer:是当前操作系统的基本时间单位,默认会根据当前运行环境的操作系统自动获取(源码中已经定义),保持默认即可。
    • number:要测试代码的运行次数,默认1000000(一百万)次,可以自己修改运行次数。
    • globals:是执行的命名空间。

    timeit.default_timer():默认的计时器,也就是time.perf_counter()

    class timeit.Timer(stmt='pass', setup='pass', timer=, globals=None):用于进行代码执行速度测试的计时类。该类有四个方法:

    • timeit(number=1000000)
    • autorange(callback=None)
    • repeat(repeat=3, number=1000000)
    • print_exc(file=None)

    备注:stmt 参数setup 参数 默认值都是 pass,如果不传值,那么就失去了测试的意义,所以这两个参数是必要的。

    1.2 timeit.repeat()函数:指定重复次数的执行timeit方法,返回一个结果列表。

    基本语法:

    timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)
    

    参数说明:

    • repeat:表示测试要重复几次,可以理解为将相同参数的 timeit() 函数重复执行。最终的结果构成一个列表返回,repeat 默认为3次。

    二、在命令行command中执行timeit命令,计算程序运行时间

    命令行界面:

    当从命令行调用程序时,将使用以下形式:

    python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
    

    参数说明:

    • -n N, --number=N:执行次数;
    • -r N, --repeat=N:计时器重复次数(默认值3);
    • -s S, --setup=S:执行环境配置(通常该语句只被执行一次,默认pass);
    • -t, --time:使用time.time()(除Windows以外的所有平台上的默认);
    • -c, --clock:使用time.clock()(在Windows上默认);
    • -v, --verbose:打印原始时间结果,得到更多数字精度;
    • -h, --help:帮助;
    (1)计算输出形如:'0_1_2...'的时间
    python3 -m timeit '"_".join(str(n) for n in range(100))'
    >>>
    20000 loops, best of 5: 18.5 usec per loop
    (2)计算输出形如:'0_1_2...'的时间
    python3 -m timeit '"-".join([str(n) for n in range(100)])'
    >>>
    20000 loops, best of 5: 16.4 usec per loop
    (3)计算输出形如:'0_1_2...'的时间
    python3 -m timeit '"_".join(map(str, range(100)))'
    >>>
    20000 loops, best of 5: 13.3 usec per loop
    
    python -m timeit -s 'text = "sample string"; char = "g"'  'char in text'
    >>>
    10000000 loops, best of 5: 27.5 nsec per loop
    
    
    import timeit
    t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
    t.timeit()
    >>>
    0.060282987000391586
    

    三、在Python程序内部调用timeit模块,计算程序运行时间

    3.1. 测试单/多行语句的执行时间:

    # 测试单行语句执行时间
    import timeit
    timeit.timeit('"_".join(map(str, range(100)))',number=10)
    >>>
    0.0002646529974299483
    timeit.timeit('"_".join(str(n) for n in range(100))',number=10)
    >>>
    0.0005391980012063868
    timeit.timeit('"_".join([str(n) for n in range(100)])',number=10)
    >>>
    0.000366011998266913
    
    # 测试多行语句执行时间
    import timeit
    s = """\
    try:
        int.__bool__
    except AttributeError:
        pass
    """
    timeit.timeit(stmt=s, number=100000)
    

    3.2. 在方法内通过setup参数指定调用对象:

    示例1def test():
        """Stupid test function"""
        L = []
        for i in range(100):
            L.append(i)
    
    if __name__ == '__main__':
        import timeit
        print(timeit.timeit("test()", setup="from __main__ import test"))
    
    >>>
    6.578784502999952
    
    ## 或者
    def test():
    	"""Stupid test function"""
        L = [i for i in range(100)]
    
    if __name__ == '__main__':
        import timeit
    	print(timeit.timeit("test()", setup="from __main__ import test"))
    >>>
    3.24046479000026
    
    示例2def matrix():
        """矩阵乘法运算"""
        import torch
        M = torch.rand(10, 10)
        M.mm(M).mm(M)
    if __name__ == '__main__':
        import timeit
        print(timeit.timeit("matrix()",number=3, setup="from __main__ import matrix"))
    >>>
    0.001695301000154359
    

    3.3. 通过globals参数指定运行空间:

    def f(x):
        return x**2
    def g(x):
        return x**4
    def h(x):
        return x**8
    
    import timeit
    print(timeit.timeit('[func(42) for func in (f,g,h)]', globals=globals()))
    >>>
    1.3725472270016326
    

    参考链接:timeit

    完整示例:

    # coding=utf-8
    def insert_time_test():
        insert_list = list()
        for i in range(10):
            insert_list.insert(0, i)
      
    
    def append_time_test():
        append_list = list()
        for i in range(10):
            append_list.append(i)
     
    if __name__ == '__main__':
        import timeit
    
    insert_time_timeit = timeit.timeit(stmt='insert_time_test()', 
                                       setup='from __main__ import insert_time_test')
    print('insert_time_timeit: ', insert_time_timeit)
    append_time_timeit = timeit.timeit(stmt='append_time_test()', 
                                       setup='from __main__ import append_time_test')
    print('append_time_timeit: ', append_time_timeit)
    >>>
    insert_time_timeit:  1.5472285019968695
    append_time_timeit:  1.0619552210009715
    
    
    insert_time_timeit = timeit.timeit(stmt='list(insert_list.insert(0, i) for i in init_list)',
                                       setup='insert_list=list();init_list=range(10)',
                                       number=100000)
    print('insert_time_timeit: ', insert_time_timeit)
    append_time_timeit = timeit.timeit(stmt='list(append_list.append(i) for i in init_list)',
                                       setup='append_list=list();init_list=range(10)',
                                       number=100000)
    print('append_time_timeit: ', append_time_timeit)
    >>>
    insert_time_timeit:  416.30776414700085
    append_time_timeit:  0.3249605919991154
    
    
    insert_time_repeat = timeit.repeat(stmt='insert_time_test()',
                                       setup='from __main__ import insert_time_test')
    print('insert_time_repeat: ', insert_time_repeat)
    append_time_repeat = timeit.repeat(stmt='append_time_test()',
                                       setup='from __main__ import append_time_test')
    print('append_time_repeat: ', append_time_repeat)
    >>>
    insert_time_repeat:  [1.5643876249996538, 1.573867484999937, 1.5350732170008996, 1.4930691439985821, 1.613208124999801]
    append_time_repeat:  [1.2118435169977602, 1.1756933159995242, 1.2724871930004156, 1.27145235900025, 1.3099699200029136]
    

    在使用timeit模块时,可以直接使用timeit.timeit()、tiemit.repeat(),还可以先用timeit.Timer()来生成一个Timer对象,然后再用TImer对象用timeit()和repeat()函数,后者再灵活一些。

    一、直接使用timeit.timeit()、tiemit.repeat():

    import timeit 
    
    print(timeit.timeit(stmt= 'list(i**2 for i in normal_list)',setup = 'normal_list=range(10000)',number=10))
    #0.3437936799875755
    print(timeit.repeat(stmt= 'list(i**2 for i in normal_list)', setup='normal_list=range(10000)',repeat=2,number=10))
    #[0.33649995761778984, 0.3394490767789293]
    #setup 为复合语句
    print(timeit.timeit(stmt= 'list(i**2 for i in normal_list)',setup = 'a=10000;normal_list=range(a)',number=10))
    #0.33272367424748817
    print(timeit.repeat(stmt= 'list(i**2 for i in normal_list)', setup='a=10000;normal_list=range(a)',repeat=2,number=10))
    #[0.3323106610316342, 0.3356380911962764]
    
    def func():
        normal_list=range(10000)
        L = [i**2 for i in normal_list]
    
    #stmt为函数
    print(timeit.timeit("func()", setup="from __main__ import func",number=10))
    #0.12436874684622312
    print(timeit.repeat("func()", setup="from __main__ import func",repeat=2,number=10))
    #[0.12142133435126468, 0.12079555675148601]
    
    

    直接用函数的方式,速度更快。

    二、先生成Timer,再调用timeit()、repeat():

    import timeit 
    
    #生成timer
    timer1 = timeit.Timer(stmt= 'list(i**2 for i in normal_list)',setup = 'normal_list=range(10000)')
    #调用timeit和repeat时还传number和repeat参数
    print(timer1.timeit(number=10))
    #0.34721554568091145
    print(timer1.repeat(repeat=2,number=10))
    #[0.3391925079630199, 0.34103400077255097]
    
    #setup 为复合语句
    timer1 = timeit.Timer(stmt= 'list(i**2 for i in normal_list)',setup = 'a=10000;normal_list=range(a)')
    print(timer1.timeit(number=10))
    0.34383463997592467
    print(timer1.repeat(repeat=2,number=10))
    #[0.34573984832288773, 0.34413273766891006]
    
    #stmt为函数
    def func():
        normal_list=range(10000)
        L = [i**2 for i in normal_list]
    
    timer1 = timeit.Timer("func()", setup="from __main__ import func")
    print(timer1.timeit(number=10))
    #0.1223264363160359
    print(timer1.repeat(repeat=2,number=10))
    #[0.12266321844246209, 0.1264150395975001]
    
    

    Python官方教程关于timeit模块具体可参见文档:

    http://docs.python.org/library/timeit.html

    https://docs.python.org/zh-cn/3/library/timeit.html

    四、附录:常见用法

    time.clock() 计算的是 CPU 的时间,在 windows 平台上精度比较高
    time.time() 计算的是程序的运行时间,会受到机器负载的影响,除了 windows 以外的平台精度比较高。

    所以我们可以按照平台来使用不同的方法。

    # 选择不同运行平台下的计数器
    import time
    import sys
    
    if sys.platform == "win32":
        # On Windows, the best timer is time.clock()
        default_timer = time.clock
    else:
        # On most other platforms the best timer is time.time()
        default_timer = time.time
    
    import timeit
    # 通过开始、结束的时间差,得到程序某函数段的运行时间
    b = timeit.default_timer()
    # to some
    e = timeit.default_timer()
    print(e - b)
    >>>
    7.159800225053914e-05
    

    参考链接:Python 计时器 timeit

  • 相关阅读:
    JavaScript动画库:Anime.js
    jdbc-plus是一款基于JdbcTemplate增强工具包, 基于JdbcTemplate已实现分页、多租户等插件,可自定义扩展插件
    「Qt Widget中文示例指南」如何创建一个计算器?(一)
    SpringSecurity 总结
    设计模式——结构型模式(静态代理、JDK动态代理)
    java中数据类型byte的底层原理透析
    vue3项目学习一:创建vue3项目
    【GO】LGTM_Grafana_Tempo(2)_官方用例改后实操
    同步代码和异步代码
    简单实现接口自动化测试(基于python)
  • 原文地址:https://blog.csdn.net/weixin_42782150/article/details/127088599