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

猜你喜欢

转载自blog.csdn.net/weixin_42782150/article/details/127088599