timeit模块 - 度量小段代码片的执行时间

官方文档: 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=3number=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=3number=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"))

你可能感兴趣的:(python,timeit)