官方文档: https://docs.python.org/2/library/timeit.html
源代码片: Lib/timeit.py
该模块提供了简单的方式来测量小段Python代码片.它有两种执行方式:命令行接口执行方式 和 Python程序代码可调的函数的方式.
该模块避免了很多常见的度量时间的陷进.可以参考由O’Reilly出版的Python Cookbook里面介绍算法章节。
1. 基本的例子
下面例子可以展示如果使用Command-Line Interface比较三种不同的表达式
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop
同样可以用Python Interface来实现:
>>>
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.7288308143615723
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.5858950614929199
注意:模块只有用Command-Line Interface方式才会自动判断重复的次数,在详细的例子部分可以找到更多高级的例子
2. Python接口方式
该模块定义了三个便利的函数和一个公共类:
-
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
-
用已给的语句创建一个Timer实例,setup 代码、timer函数、 运行带有number执行次数的timeit()方法.
-
timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)
-
用已给的语句创建一个Timer实例,setup 代码、timer函数、 运行带有number执行次数和repeat次数的的repeat()方法.
-
timeit.default_timer()
-
定义一个基于特别平台的默认的计时器,在Windwos系统,time.clock()有微妙的精度,但是time.time()只有1/60秒的精度.在Unix统,time.clock()有1/100秒的精度,而time.time()的精度更高.在任意一个平台,default_timer()度量墙上物理时钟时间.而不是CPU时间,这意味着计时时,运行在同一台计算机上的其他进程可能会中断
-
class timeit.Timer(stmt='pass', setup='pass', timer=<timer function>) 计算小片代码段的类
-
构造函数用一个语句来做计时操作,用一个附加的语句来setup,还有一个计时函数,默认设置为:'pass';
-
计时器函数依赖于具体平台(可以参考模式的doc文档)stmt 和 setup可以包括多个语句,以分号隔开;
-
或者新行,只要没有包括多行字符串迭代.
-
-
要测量第一个语句的执行时间,用timeit()方法.repeat()方法很方便调用多次timeit(),并返回一个结果集的列表.
-
版本2.6改动:stmt 和 setup参数同样可以调用无参的可调用的对象.这种嵌套调用会被timeit()执行. NOTE:这样做的话会增加额外的开销,既然有额外的函数调用.
-
-
timeit(number=1000000)
-
在一个主语句中计时次数.该语句会先执行一次setup语句,然后返回主语句中实际执行的次数,以浮点的秒数来度量,这个参数是主语句中循环次数,默认是1百万次.
-
Note:
在计时时,默认,timeit() 临时关闭垃圾回收功能.这样做的好处是:独立计时让其更具有可比性.这样做不好的地方在于:GC也许是函数表现的一部分,必须同样要进行测试,如果这样的话,GC功能可以作为setup字符串变量的开始部分来激活,例如:
timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
-
repeat(repeat=3, number=1000000)
-
调用timeit()数次.这是一个方便的方法,可以重复调用,返回一个结果集,以列表的方式显示。第一个参数是调用timeit()次数,第二个参数是timeit()中的计时参数;
-
print_exc(file=None)
-
帮助打印从计时代码中的traceback,典型使用:
t = Timer(...) # 在try/except语句外使用
try:
t.timeit(...) # 或t.repeat(...)
except:
t.print_exc()
这样做的好处是,可以将参数file直接定位到traceback,默认是:sys.stderr.
3. 命令行接口方式
当在命令行方式执行时,命令如下
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
-
打印原始计时结果;重复打印多个高精度的数字.
-
D:\>python -m timeit -v "'_'.join(str(n) for n in range(1000))"
10 loops -> 0.00329 secs
100 loops -> 0.035 secs
1000 loops -> 0.324 secs
raw times: 0.327 0.33 0.325
1000 loops, best of 3: 325 usec per loop
-
-h, --help
-
打印简短的使用信息并离开
4. 详细的例子
它提供了setup语句,在命令行方式中,程序执行的开始
$ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text'
10000000 loops, best of 3: 0.0877 usec per loop
$ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)'
1000000 loops, best of 3: 0.342 usec per loop
>>>
>>> import timeit
>>> timeit.timeit('char in text', setup='text = "sample string"; char = "g"')
0.41440500499993504
>>> timeit.timeit('text.find(char)', setup='text = "sample string"; char = "g"')
1.7246671520006203
同样可以用Timer类和它们的方法来实现
>>>
>>> import timeit
>>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
>>> t.timeit()
0.3955516149999312
>>> t.repeat()
[0.40193588800002544, 0.3960157959998014, 0.39594301399984033]
下面的例子示范如果测量多行表达式的执行时间,这里主要比较 hasattr() vs try/except来测试缺省或存在两种情况下的对象属性的时间消耗.
$ python -m timeit 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass'
100000 loops, best of 3: 15.7 usec per loop
$ python -m timeit 'if hasattr(str, "__nonzero__"): pass'
100000 loops, best of 3: 4.26 usec per loop
$ python -m timeit 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass'
1000000 loops, best of 3: 1.43 usec per loop
$ python -m timeit 'if hasattr(int, "__nonzero__"): pass'
100000 loops, best of 3: 2.23 usec per loop
>>>
>>> import timeit
>>> # 属性缺省的情况
>>> s = """\
... try:
... str.__nonzero__
... except AttributeError:
... pass
... """
>>> timeit.timeit(stmt=s, number=100000)
0.9138244460009446
>>> s = "if hasattr(str, '__bool__'): pass"
>>> timeit.timeit(stmt=s, number=100000)
0.5829014980008651
>>>
>>> # 属性存在的情况
>>> s = """\
... try:
... int.__nonzero__
... except AttributeError:
... pass
... """
>>> timeit.timeit(stmt=s, number=100000)
0.04215312199994514
>>> s = "if hasattr(int, '__bool__'): pass"
>>> timeit.timeit(stmt=s, number=100000)
0.08588060699912603
如果想让timeit模块测量你定义的函数,可以传递一个setup参数,该参数包括一个import语句:
def test():
L = []
for i in range(100):
L.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))