在命令行使用python的timeit模块

2019年11月11日 / 5次阅读 / Last Modified 2019年11月13日
时间计算

python自带的timeit模块,用来测量一小段代码的执行时间。本文详细介绍如何在命令行使用这个模块,以及对应的各种参数。在命令行直接运行python的模块,需要使用-m参数,请参考:关于python的-m参数

直接用测试用例来说明吧:

$ python3 -m timeit '[str(n) for n in range(100)]'
20000 loops, best of 5: 15 usec per loop

使用python的-m参数,直接运行timeit模块,后跟一个括起来的python表达式(这是一个list comprehension,得到一个从0到99的字符串list),这行命令的作用,就是测试这一行表达式在当前的环境下的执行时间。我们可以看到timeit模块显示出来的结果,每次执行了20000次,共执行5次,最好的1次,平均每loop是15 usec(15微秒,20000 loops,best of 5的意思是一共repeat了5次,5次是默认值,每一次20000 loops,取最好的那一次来平均)。15 usec就是这一行python表达式的执行时间。

执行20000次,这个数字式timeit模块自己测算出来的,测算规则式按照10的N次方来执行命令行中的表达式,N从小到大,直到执行的总时间大于0.2秒。如果我们稍微修改一下表达式,就会得到不一样的loops次数:

$ python3 -m timeit '[str(n) for n in range(1000)]'
2000 loops, best of 5: 165 usec per loop

将测试的python表达式的list长度增大10倍,timeit这次每个循环只执行了2000个loop,最好的1次平均为165 usec。

timeit模块有两个参数,可以用来自己控制表达式的执行测试,-n和-r,分别用来控制每次的loop次数,和repeat的次数:

$ python3 -m timeit -n 800 -r 9 '[str(n) for n in range(100)]'
800 loops, best of 9: 14.6 usec per loop

-n 800,指定每次执行800个loop,-r 9,指定一共repeat 9次!

现在,我要解释一下使用timeit得到的时间是什么时间。默认情况下,timeit得到的时间是wallclock时间。什么是wallclock时间?就是实际经过的时间,这段时间CPU可能进行了很多次中断,很多次进程的切换等等,这些时间都算在了里面。你一定会觉得如果按照wallclock时间来测量python表达式的执行时间,是不精确的。timeit模块提供了一个 -p 参数,可以让我们使用CPU时间,即process time,这样得到的结果一般会更小,但是也更精确,更加有可比较性。

$ python3 -m timeit -p '[str(n) for n in range(100)]'
20000 loops, best of 5: 14.6 usec per loop

得到的时间变成了14.6 usec,小了一点点!

还有一个 -u 参数,用来执行结果中时间的单位:

$ python3 -m timeit -u '[str(n) for n in range(100)]'
Unrecognized unit. Please select nsec, usec, msec, or sec.
$ python3 -m timeit -u msec '[str(n) for n in range(100)]'
20000 loops, best of 5: 0.0147 msec per loop

如果使用 -v 参数,跟很多命令行的程序一样,-v表示verbose,能够得到更详细的显示信息:

$ python3 -m timeit -v '[str(n) for n in range(100)]'
1 loop -> 1.77e-05 secs
2 loops -> 3.28e-05 secs
5 loops -> 7.52e-05 secs
10 loops -> 0.000147 secs
20 loops -> 0.000289 secs
50 loops -> 0.000731 secs
100 loops -> 0.00145 secs
200 loops -> 0.00303 secs
500 loops -> 0.00747 secs
1000 loops -> 0.0149 secs
2000 loops -> 0.0298 secs
5000 loops -> 0.0757 secs
10000 loops -> 0.149 secs
20000 loops -> 0.296 secs

raw times: 300 msec, 293 msec, 295 msec, 296 msec, 294 msec

20000 loops, best of 5: 14.6 usec per loop

最后来介绍 -s 参数。这个参数极大的提高了在命令行使用timeit模块的价值。-s 参数后面跟一个预先执行的python表达式,然后通过反复执行最后的表达式来测量时间,默认 -s 后面是pass。什么情况下使用 -s 参数?比如我们需要测量某个自己编写的函数,这个函数在某个.py文件内,在python的执行环境中,需要先import这个模块文件,才能调用函数。

$ python3 -m timeit -s 'import misc' '[misc.ehex(n) for n in range(100)]'
5000 loops, best of 5: 42.3 usec per loop

上面的示例,通过 -s 参数import一个模块,然后测试的是这个模块中的ehex函数的执行时间。

下面介绍如何用timeit测试多行代码:

$ python3 -m timeit '
> a = 123
> b = 456
> for i in range(10000): a**b
> '
10 loops, best of 5: 24.8 msec per loop

直接换行书写即可!

另一种风格是使用python支持的分号(;)来实现多行代码。

-s 参数可以有多个:

$ python3 -m timeit -s 'import random' -s 'import re' python-expression

如果python表达式中有单引号,这时最外面就要使用双引号来将整个表达式括起来:

$ python3 -m timeit "'.'.join([str(n) for n in range(100)])"
20000 loops, best of 5: 16.5 usec per loop

关于在命令行中使用python的timeit模块,基本上就是这些内容了!

-- EOF --

本文链接:https://www.pynote.net/archives/1481

留言区

电子邮件地址不会被公开。 必填项已用*标注


前一篇:
后一篇:

More

麦新杰的Python笔记

Ctrl+D 收藏本页


©Copyright 麦新杰 Since 2019 Python笔记

go to top