timeit库文档:https://docs.python.org/zh-cn/3/library/timeit.html
timeit 是一个用来测量小代码片段执行时间的工具库,有命令行和函数调用两种方法可供使用。
可以直接查看文档最后的示例部分快速了解其用法。 注意:
- 使用函数调用时,timeit()方法的返回值以秒为单位,而且返回的是代码语句运行number次(timeit方法的参数)的总耗时,不是多次运行取最好结果/平均结果。
- 在在命令行中,使用timeit语句返回结果是多次循环所花费的平均时间,时间单位可以指定。
基本示例:
需要注意的是,在命令行,传给timeit 的 stmt 参数 (即要运行的测试代码)都要是字符串格式的,而不是函数引用或Python语句。在函数中,除了字符串,可以传入一个可调用对象。
-
命令行方式: 如果是在windows下使用命令行执行语句,切记最外层需要使用双引号 ,否则会报错。 $ python3 -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 5: 30.2 usec per loop
$ python3 -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 5: 27.5 usec per loop
$ python3 -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 5: 23.2 usec per loop
-
函数调用: >>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.3018611848820001
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.2727368790656328
>>> timeit.timeit('"-".join(map(str, range(100)))', number=10000)
0.23702679807320237
在函数调用时,可以传入可调用对象: >>> timeit.timeit(lambda: "-".join(map(str, range(100))), number=10000)
0.19665591977536678
但是请注意,timeit ()只有在使用命令行界面时才会自动确定重复次数。
Python接口(函数调用)的使用方法:
模块包含3个常用方法和一个Timer类:
-
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None) 使用给定的stmt、setup代码和timer函数创建一个 Timer 实例,并根据number运行它的 timeit ()方法。可选的 globals 参数指定在其中执行代码的命名空间。 -
timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=5, number=1000000, globals=None) 使用给定的stmt和setup代码和timer函数创建一个 Timer 实例,并使用给定的repeat计数和number执行运行它的 repeat ()方法(默认执行5 * 1000000次)。可选的 globals 参数指定在其中执行代码的命名空间。 -
timeit.default_timer() 默认的计时器 time.perf_counter() . -
*class* timeit.Timer(stmt='pass', setup='pass', timer=<timer function>, globals=None) 用于计时小代码端执行速度的类。该类包括timeit(), autorange(), repeat()和print_exec() 四个方法。 构造函数接受一条要计时的语句stmt、一条用于设置的附加语句setup和一个计时器函数。这两个语句都默认为“ pass”; 计时器函数依赖于平台。Stmt 和 setup 还可以包含由; 或换行分隔的多个语句,只要它们不包含多行字符串文字。默认情况下,语句将在其名称空间内执行; 可以通过将名称空间传递给globals变量来控制此行为。 若要度量第一个语句stmt的执行时间,请使用 timeit ()方法。Repeat ()和 autOrange ()方法是方便多次调用 timeit ()的方法。setup语句的执行时间被排除在整个计时执行运行之外。 Stmt 和 setup 参数还可以接受不带参数的可调用对象(callable)。这将把对它们的调用嵌入到一个计时器函数中,然后由 timeit ()执行。注意,在这种情况下,由于额外的函数调用,计时开销有点大。
-
timeit(number=1000000) : 主语句的执行时间。这会执行 setup 语句一次,然后返回执行主语句若干次所需的时间,以秒为单位作为浮点数进行计算。参数是通过循环的次数,默认为100万次。主语句、 setup 语句和要使用的 timer 函数被传递给构造函数。 注意:在使用timeit()函数测试时,默认会临时关闭Python的垃圾回收功能。这种方法的优点是它使独立计时更具可比性。缺点是 GC 可能是被测量函数性能的重要组成部分。如果是这样,GC 可以作为设置字符串中的第一条语句重新启用。 timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit() 在创建Timer对象时的stmt中设置gc.enable() 。 -
autorange(callback=None) : 自动确定调用 timeit ()的次数。 这是一个便捷函数,用来反复调用 timeit () ,使总时间 > = 0.2秒,返回最终结果(循环次数和循环花费的时间)。它使用序列1、2、5、10.20、50中的递增数字调用 timeit () ,直到所花费的时间至少为0.2秒。 如果回调callback是给定的,并且不是 None,那么在每次试验之后将使用两个参数调用它: callback (number,time_taken) 。 -
repeat(repeat=5, number=1000000) : 调用计时器repeat次。 这是一个便捷函数,它重复调用 timeit () ,返回一个结果列表。第一个参数repeat指定调用 timeit ()的次数。第二个参数指定 timeit ()的 number 参数。 注意:从结果向量计算平均值和标准差并报告这些结果是很有诱惑力的。然而,这并不是很有用。在一个典型的例子中,最低值给出了您的计算机运行给定代码片段的速度的下限; 结果向量中较高的值通常不是由 Python 速度的变化引起的,而是由于其他进程干扰了计时的准确性。因此,结果的 min ()可能是您应该感兴趣的唯一数字。之后,您应该用常识看待整个向量而不是从统计的角度看待整个结果。 -
print_exc(file=None) : 从计时代码打印回溯的帮助程序。 t = Timer(...)
try:
t.timeit(...)
except Exception:
t.print_exc()
相对于标准回溯的优势在于,将显示已编译模板中的源代码行。可选的 file 参数指向发送回溯的位置; 它默认为 sys.stderr。
命令行接口:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]
-n timer执行statement的次数
-r 重复执行timer的次数,默认为5
-u 指定timer输出的时间格式,可以指定为:nsec、usec、msec、sec
-s setup 语句,默认为pass
-p 使用time.process_time()而不是默认的time.perf_counter()来度量进程时间,而不是墙钟时间
-v 详细信息,打印原始的计时结果
-h 帮助信息
一个多行的statement可以通过使用 ; 分给为多个语句,带缩进的行可以使用引号括起一个参数并使用前导空格。-s选项的多行语法是类似的。
示例:
$ python -m timeit -s 'text = "sample string"; char = "g"' 'char in text'
5000000 loops, best of 5: 0.0877 usec per loop
$ python -m timeit -s 'text = "sample string"; char = "g"' 'text.find(char)'
1000000 loops, best of 5: 0.342 usec per loop
使用-s 指定的setup语句只在开始时执行一次。 在输出中有三个字段:
- loop count:告诉您每次计时循环重复运行语句体的次数。
- repetition count:(best of 5)告诉您计时循环重复的次数。
- 平均耗时:语句主体在计时循环的最佳重复范围内所花费的平均时间。
以上语句使用函数和Timer类的代码如下:
>>> 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
>>> import timeit
>>> t = timeit.Timer('char in text', setup='text = "sample string"; char = "g"')
>>> t.timeit()
0.3955516149999312
>>> t.repeat()
[0.40183617287970225, 0.37027556854118704, 0.38344867356679524, 0.3712595970846668, 0.37866875250654886]
多行语句:
当statement语句中包含多行语句时,在命令行和Python代码中可以如下执行:
$ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass'
20000 loops, best of 5: 15.7 usec per loop
$ python -m timeit 'if hasattr(str, "__bool__"): pass'
50000 loops, best of 5: 4.26 usec per loop
$ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass'
200000 loops, best of 5: 1.43 usec per loop
$ python -m timeit 'if hasattr(int, "__bool__"): pass'
100000 loops, best of 5: 2.23 usec per loop
>>> import timeit
>>>
>>> s = """\
... try:
... str.__bool__
... 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.__bool__
... 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
测试函数运行时间:
当要对我们定义的函数进行时间测量时,可以通过setup参数传递脚本中需要的 import 语句(即使是在当前脚本下也要import:from __main__ import func ),stmt 参数传递方法调用字符串化后的表达式:
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"))
另一种方法是向globals参数传递 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()))
函数调用与命令行调用返回结果的差异:
- 函数调用中timeit()方法的返回值,单位为秒,而且返回的是运行number次的总用时,不是平均用时。
- 命令行中返回的结果是循环的平均用时,单位可以自行指定。
In [2]: def test():
...: a = 0
...: for _ in range(1000):
...: a += _
...:
In [3]: timeit.timeit('test()', globals=globals())
Out[3]: 35.442787599982694
In [4]: timeit.timeit('test()', number=1, globals=globals())
Out[4]: 3.50000336766243e-05
In [5]: timeit.timeit('test()', number=10, globals=globals())
Out[5]: 0.00033359997905790806
In [6]: timeit.timeit('test()', number=100, globals=globals())
Out[6]: 0.0032857999904081225
In [7]: timeit.timeit('test()', number=1000, globals=globals())
Out[7]: 0.03538430004846305
>python -m timeit "a=0" "for _ in range(1000):" " a+=_"
10000 loops, best of 5: 32.4 usec per loop
>python -m timeit -u sec "a=0" "for _ in range(1000):" " a+=_"
10000 loops, best of 5: 3.24e-05 sec per loop
|