测试代码执行时间的模块-timeit

Posted yungiu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了测试代码执行时间的模块-timeit相关的知识,希望对你有一定的参考价值。

有时候我们想看看一个函数的执行时间是多久,这时候我们可以使用装饰器,在函数的执行开始前,记录一个时间,在函数的执行结束后记录一个时间,然后求两个数的差,就可以得到这个函数本次的执行时间了。但是这样做的做法,太Low,接下来我们就说说Python 内置的timeit 模块

timeit 模块可以用来测试一小段Python 代码的执行速度
timeit 模块里面有一个Timer 类,首先需要实例化这个类,先看一下初始化这个类所可以接收的参数,下面是timeit 模块关于Timer 的源码

1 class Timer:
2     ...
3     def __init__(self, stmt="pass", setup="pass", timer=default_timer, globals=None)
4     ...

资料显示这个是Python2.3 更新的一个完美计时工具,可以测量Python 代码的运行时间。
首先Timer 是这个测量代码执行时间的类
这个类实例化时可接收的参数
    stmt:要测试的代码语句(statment)
    setup:运行代码时需要的设置,也就是要测试代码的前置条件
    timer:参数时一个定时器函数,与平台有关
    globals:待查,后续更新


这个类实例出来后有两个方法是我们经常用到的

Timer.timeit(number=default_number)
参数number 是测试代码时的测试次数,默认default_number 为1000000 次,这个方法返回执行代码的耗时,一个float 类型的秒数。

Timer.repeat(repeat=default_repeat, number=default_number)
参数repeat 是重复整个测试的次数,默认是重复3 次,参数number 是每个测试代码时的测试次数,默认也是1000000 次,
这个方法返回一个列表,元素的个数就是重复整个测试的次数,每个元素值就是每个测试代码的耗时,是一个float 类型的秒数。

由简单着手,具体如下:

 1 import timeit 
 2 # 创建timeit 对象
 3 timer_hello = timeit.Timer("print(‘hello‘))
 4 # 调用timer 方法执行1000 次,并打印结果
 5 time_use = time_hello.timeit(1000)
 6 print(elapse :{}.format(time_use))
 7 
 8 
 9 hello
10 ...
11 hello
12 elapse :0.07077193709161148

但是事实上没人会测试打印1000 次“hello”所用的时间,除非特别无聊,举这个例子只是为了方便直观的说明第二个参数的作用

 1 import timeit
 2 
 3 a = hello
 4 
 5 timer_a = timeit.Timer("print(a)")
 6 time_use = time_a.timeit(1000)
 7 print(elapse :{}.format(time_use))
 8 
 9 
10 ...
11 NameError: name a is not defined

为什么会这样呢?明明已经定义了变量a 啊,为什么还是提示未定义?
这是因为这个类实例话的时候,会构建一个独立的虚拟空间用于测试待测试代码
只需要传入第二个参数就可以解决这个问题

 1 import timeit
 2 
 3 # a = ‘hello‘
 4 
 5 timer_a = timeit.Timer("print(a)",“a=hello”)
 6 time_use = time_a.timeit(1000)
 7 print(elapse :{}.format(time_use))
 8 
 9 hello
10 ...
11 elapse :0.038286632634104326
12 # 时间上会比直接打印‘hello’要稍微长一点

这样就没问题了,可是我们当初的目的是用来打印一个函数啊,难不成要在第二个参数上写一个函数,比如匿名函数f = lambda :print(‘hello’)?

 1 import timeit
 2 
 3 # a = ‘hello‘
 4 
 5 timer_a = timeit.Timer("f()",“f=lambda : print(hello)”)
 6 time_use = time_a.timeit(1000)
 7 print(elapse :{}.format(time_use))
 8 
 9 hello
10 ...
11 elapse :0.014775986865789454

也没问题,但是这只是个简单的函数,如果函数的逻辑很复杂,代码量很多,这样就不太好用了,那怎么办呢?答案是导入,将当前模块导入到这个Timer 实例对象的环境中就行了

 1 import timeit
 2 
 3 # a = ‘hello‘
 4 def print_hello():
 5     print(hello)
 6 
 7 timer_a = timeit.Timer("print_hello()",“from __main__ import print_hello”)
 8 time_use = time_a.timeit(1000)
 9 print(elapse :{}.format(time_use))
10 
11 
12 hello
13 ...
14 elapse :0.038094632804770844

 

下面是Python 中list 的一些操作测试

 1 def t1():
 2     l = []
 3     for i in range(1000):
 4     l = l + [i]
 5 def t2():
 6     l = []
 7     for i in range(1000):
 8     l.append(i)
 9 def t3():
10     l = [i for i in range(1000)]
11 def t4():
12     l = list(range(1000))
13 
14 import timeit
15 
16 time_t1 = timeit.Timer(t1(), from __main__ import t1)
17 print(concat use {} seconds.format(time_t1.timeit(1000)))
18 time_t2 = timeit.Timer(t2(), from __main__ import t2)
19 print(append use {} seconds.format(time_t2.timeit(1000)))
20 time_t3 = timeit.Timer(t3(), from __main__ import t3)
21 print(comprehension use {} seconds.format(time_t3.timeit(1000)))
22 time_t4 = timeit.Timer(t4(), from __main__ import t4)
23 print(list range use {} seconds.format(time_t4.timeit(1000)))
24 
25 concat use 1.1694602938130723 seconds
26 append use 0.0634083880814329 seconds
27 comprehension use 0.028811085501257327 seconds
28 list range use 0.009896880091662119 seconds

由此可以看出,Python 内置的list 函数强转的效率有多高,列表推导式仅次之,列表尾部添加元素的效率正常,而列表的拼接后重新引用的执行效率,则要差上很多了。

相对于append,我们看一下列表头部插入的执行效率

1 def t5():
2     l = []
3     for i in range(1000):
4     l.insert(0, i)
5 time_insert = timeit.Time(t5(), from __main__ import t5)
6 print(insert use {} seconds.format(time_t5.timeit(1000)))
7 
8 insert use 0.2727046464847587 seconds

可以看出列表都不插入的效率比尾部插入的效率要低的多

 

最后再来说一说repeat 方法

print(append information :{}.format(time_t2.repeat(4, 1000)))
print(insert information :{}.format(time_t5.repeat(4, 1000)))



append information :[0.06173994512004878, 0.06133461214701143, 0.06315461052923509, 0.06169727849130799]
insert information :[0.26799709511369324, 0.26826598376357, 0.2789770853537018, 0.26663220743803784]

可以看出,对这些代码的运行,进行了输入个数的测试,并返回了一个列表,元素为每个测试的结果

 














以上是关于测试代码执行时间的模块-timeit的主要内容,如果未能解决你的问题,请参考以下文章

python timeit模块

2 timeit模块,python中数据结构

数据结构性能分析(代码运行效率)

Python timeit模块的使用

timeit模块

Python timeit