timeit
— Measure execution time of small code snippets测量小代码片段的执行时间¶
Source code: Lib/timeit.py
This module provides a simple way to time small bits of Python code. 该模块提供了一种简单的方法来计时Python代码的一小部分。It has both a Command-Line Interface as well as a callable one. 它既有命令行接口,也有可调用接口。It avoids a number of common traps for measuring execution times. 它避免了许多用于测量执行时间的常见陷阱。See also Tim Peters’ introduction to the “Algorithms” chapter in the second edition of Python Cookbook, published by O’Reilly.另请参见Tim Peters对O’Reilly出版的《Python Cookbook》第二版中“算法”一章的介绍。
Basic Examples基本示例¶
The following example shows how the 以下示例显示了如何使用命令行界面比较三个不同的表达式:Command-Line Interface命令行界面 can be used to compare three different expressions:
$ 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
This can be achieved from the Python Interface with:这可以通过Python接口通过以下方式实现:
>>> 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
A callable can also be passed from the Python Interface:还可以从Python接口传递一个可调用函数:
>>> timeit.timeit(lambda: "-".join(map(str, range(100))), number=10000)
0.19665591977536678
Note however that 但是请注意,只有在使用命令行界面时,timeit()
will automatically determine the number of repetitions only when the command-line interface is used. timeit()
才会自动确定重复次数。In the Examples section you can find more advanced examples.在示例部分,您可以找到更多高级示例。
Python InterfacePython接口¶
The module defines three convenience functions and a public class:该模块定义了三个便利功能和一个公共类:
-
timeit.
timeit
(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)¶ Create a使用给定的语句、setup代码和timer函数创建一个Timer
instance with the given statement, setup code and timer function and run itstimeit()
method with number executions.Timer
实例,并运行其timeit()
方法和number执行。The optional globals argument specifies a namespace in which to execute the code.可选的globals参数指定要在其中执行代码的命名空间。Changed in version 3.5:版本3.5中更改:The optional globals parameter was added.添加了可选的globals参数。
-
timeit.
repeat
(stmt='pass', setup='pass', timer=<default timer>, repeat=5, number=1000000, globals=None)¶ Create a使用给定的语句、setup代码和timer函数创建一个Timer
instance with the given statement, setup code and timer function and run itsrepeat()
method with the given repeat count and number executions.Timer
实例,并使用给定的重复计数和执行次数运行其repeat()
方法。The optional globals argument specifies a namespace in which to execute the code.可选的globals参数指定要在其中执行代码的命名空间。Changed in version 3.5:版本3.5中更改:The optional globals parameter was added.添加了可选的globals参数。Changed in version 3.7:版本3.7中更改:Default value of repeat changed from 3 to 5.repeat的默认值从3更改为5。
-
timeit.
default_timer
()¶ The default timer, which is always默认计时器,始终为time.perf_counter()
.time.perf_counter()
。Changed in version 3.3:版本3.3中更改:time.perf_counter()
is now the default timer.现在是默认计时器。
-
class
timeit.
Timer
(stmt='pass', setup='pass', timer=<timer function>, globals=None)¶ Class for timing execution speed of small code snippets.用于计时小代码片段的执行速度的类。The constructor takes a statement to be timed, an additional statement used for setup, and a timer function.构造函数接受要计时的语句、用于设置的附加语句和计时器函数。Both statements default to这两个语句都默认为'pass'
; the timer function is platform-dependent (see the module doc string).'pass'
;计时器函数依赖于平台(参见模块文档字符串)。stmt and setup may also contain multiple statements separated bystmt和setup还可以包含多个语句,用;
or newlines, as long as they don’t contain multi-line string literals.;
或者换行,只要它们不包含多行字符串文字即可。The statement will by default be executed within timeit’s namespace; this behavior can be controlled by passing a namespace to globals.默认情况下,该语句将在timeit的命名空间内执行;可以通过将命名空间传递给globals来控制此行为。To measure the execution time of the first statement, use the要测量第一条语句的执行时间,请使用timeit()
method.timeit()
方法。Therepeat()
andautorange()
methods are convenience methods to calltimeit()
multiple times.repeat()
和autorange()
方法是多次调用timeit()
的方便方法。The execution time of setup is excluded from the overall timed execution run.setup程序的执行时间从整个定时执行运行中排除。The stmt and setup parameters can also take objects that are callable without arguments.stmt和setup参数也可以接受无需参数即可调用的对象。This will embed calls to them in a timer function that will then be executed by这将在计时器函数中嵌入对它们的调用,然后由timeit()
.timeit()
执行。Note that the timing overhead is a little larger in this case because of the extra function calls.请注意,在这种情况下,由于额外的函数调用,定时开销稍大。Changed in version 3.5:版本3.5中更改:The optional globals parameter was added.添加了可选的globals参数。-
timeit
(number=1000000)¶ Time number executions of the main statement.主语句的执行次数number。This executes the setup statement once, and then returns the time it takes to execute the main statement a number of times, measured in seconds as a float.这将执行一次setup语句,然后将执行主语句所需的时间返回多次,以秒为单位,以浮点数表示。The argument is the number of times through the loop, defaulting to one million.参数是循环的次数,默认为一百万次。The main statement, the setup statement and the timer function to be used are passed to the constructor.将要使用的main语句、setup语句和计时器函数传递给构造函数。Note
By default,默认情况下,timeit()
temporarily turns off garbage collection during the timing.timeit()
在计时期间暂时关闭垃圾收集。The advantage of this approach is that it makes independent timings more comparable.这种方法的优点是,它使独立计时更具可比性。The disadvantage is that GC may be an important component of the performance of the function being measured.缺点是GC可能是被测函数性能的重要组成部分。If so, GC can be re-enabled as the first statement in the setup string.如果是,GC可以作为setup字符串中的第一条语句重新启用。For example:例如:timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
-
autorange
(callback=None)¶ Automatically determine how many times to call自动确定调用timeit()
.timeit()
的次数。This is a convenience function that calls这是一个方便的函数,它反复调用timeit()
repeatedly so that the total time >= 0.2 second, returning the eventual (number of loops, time taken for that number of loops).timeit()
,使总时间>=0.2秒,返回最终值(循环数,循环数所需的时间)。It calls它使用从序列1、2、5、10、20、50开始递增的数字调用timeit()
with increasing numbers from the sequence 1, 2, 5, 10, 20, 50, … until the time taken is at least 0.2 second.timeit()
,直到所用时间至少为0.2秒。If callback is given and is not如果给定了callback并且不是None
, it will be called after each trial with two arguments:callback(number, time_taken)
.None
,则在每次尝试后都会使用两个参数调用回调:callback(number, time_taken)
。New in version 3.6.版本3.6中新增。
-
repeat
(repeat=5, number=1000000)¶ Call多次调用timeit()
a few times.timeit()
。This is a convenience function that calls the这是一个方便的函数,它反复调用timeit()
repeatedly, returning a list of results.timeit()
,返回结果列表。The first argument specifies how many times to call第一个参数指定调用timeit()
.timeit()
的次数。The second argument specifies the number argument for第二个参数指定timeit()
.timeit()
的number参数。Note
It’s tempting to calculate mean and standard deviation from the result vector and report these.计算结果向量的平均值和标准差并报告这些值是很有诱惑力的。However, this is not very useful. In a typical case, the lowest value gives a lower bound for how fast your machine can run the given code snippet; higher values in the result vector are typically not caused by variability in Python’s speed, but by other processes interfering with your timing accuracy.然而,这不是很有用。在典型情况下,最低值给出了机器运行给定代码段的速度下限;结果向量中较高的值通常不是由Python速度的可变性造成的,而是由其他进程干扰您的计时精度造成的。So the因此,结果的min()
of the result is probably the only number you should be interested in.min()
可能是您应该感兴趣的唯一数字。After that, you should look at the entire vector and apply common sense rather than statistics.之后,您应该查看整个向量,并应用常识而不是统计数据。Changed in version 3.7:版本3.7中更改:Default value of repeat changed from 3 to 5.repeat的默认值从3更改为5。
-
print_exc
(file=None)¶ Helper to print a traceback from the timed code.帮助程序打印定时代码的回溯。Typical use:
t = Timer(...) # outside the try/except
try:
t.timeit(...) # or t.repeat(...)
except Exception:
t.print_exc()The advantage over the standard traceback is that source lines in the compiled template will be displayed.与标准回溯相比的优势在于,将显示编译模板中的源代码行。The optional file argument directs where the traceback is sent; it defaults to可选的file参数指示发送回溯的位置;它默认为sys.stderr
.sys.stderr
。
-
Command-Line Interface命令行界面¶
When called as a program from the command line, the following form is used:从命令行作为程序调用时,使用以下形式:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]
Where the following options are understood:如果理解以下选项:
-
-n
N
,
--number
=N
¶ how many times to execute ‘statement’执行“语句”的次数
-
-r
N
,
--repeat
=N
¶ how many times to repeat the timer (default 5)重复计时器多少次(默认值为5)
-
-s
S
,
--setup
=S
¶ statement to be executed once initially (default初始执行一次的语句(默认pass
)pass
)
-
-p
,
--process
¶
measure process time, not wallclock time, using使用time.process_time()
instead oftime.perf_counter()
, which is the defaulttime.process_time()
而不是默认的time.perf_counter()
来测量进程时间,而不是墙上时钟时间New in version 3.3.版本3.3中新增。
-
-u
,
--unit
=U
¶ specify a time unit for timer output; can select nsec, usec, msec, or sec指定计时器输出的时间单位;可以选择nsec、usec、msec或secNew in version 3.5.版本3.5中新增。
-
-v
,
--verbose
¶
print raw timing results; repeat for more digits precision打印原始计时结果;重复以获得更多数字精度
-
-h
,
--help
¶
print a short usage message and exit打印简短的使用信息并退出
A multi-line statement may be given by specifying each line as a separate statement argument; indented lines are possible by enclosing an argument in quotes and using leading spaces. 多行语句可以通过将每一行指定为单独的语句参数来给出;通过将参数括在引号中并使用前导空格,可以缩进行。Multiple 多个-s
options are treated similarly.-s
选项的处理方式类似。
If 如果没有给出-n
is not given, a suitable number of loops is calculated by trying increasing numbers from the sequence 1, 2, 5, 10, 20, 50, … until the total time is at least 0.2 seconds.-n
,则通过尝试从序列1、2、5、10、20、50增加数字来计算合适的循环数,直到总时间至少为0.2秒。
default_timer()
measurements can be affected by other programs running on the same machine, so the best thing to do when accurate timing is necessary is to repeat the timing a few times and use the best time. 测量可能会受到同一台机器上运行的其他程序的影响,因此在需要精确计时时,最好的做法是重复几次计时并使用最佳时间。The -r
option is good for this; the default of 5 repetitions is probably enough in most cases. -r
选项对此很有用;在大多数情况下,默认5次重复可能就足够了。You can use 您可以使用time.process_time()
to measure CPU time.time.process_time()
来测量CPU时间。
Note
There is a certain baseline overhead associated with executing a pass statement. 执行pass语句会产生一定的基线开销。The code here doesn’t try to hide it, but you should be aware of it. 这里的代码并没有试图隐藏它,但您应该意识到这一点。The baseline overhead can be measured by invoking the program without arguments, and it might differ between Python versions.基线开销可以通过在没有参数的情况下调用程序来测量,并且在Python版本之间可能有所不同。
Examples示例¶
It is possible to provide a setup statement that is executed only once at the beginning:可以提供一个仅在开头执行一次的设置语句:
$ 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
In the output, there are three fields. 在输出中,有三个字段。The loop count, which tells you how many times the statement body was run per timing loop repetition. 循环计数,它告诉每次重复计时循环时语句体运行了多少次。The repetition count (‘best of 5’) which tells you how many times the timing loop was repeated, and finally the time the statement body took on average within the best repetition of the timing loop. 重复计数(“最佳5次”),告诉计时循环重复了多少次,以及语句体在计时循环最佳重复范围内平均花费的时间。That is, the time the fastest repetition took divided by the loop count.也就是说,最快重复所用的时间除以循环计数。
>>> 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
The same can be done using the 使用Timer
class and its methods:Timer
类及其方法也可以做到这一点:
>>> 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]
The following examples show how to time expressions that contain multiple lines. 以下示例显示了如何对包含多行的表达式计时。Here we compare the cost of using 这里我们比较了使用hasattr()
vs. try
/except
to test for missing and present object attributes:hasattr()
与try
/except
测试缺少和存在的对象属性的成本:
$ 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
>>> # attribute is missing
>>> 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
>>>
>>> # attribute is present
>>> 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
To give the 要让timeit
module access to functions you define, you can pass a setup parameter which contains an import statement:timeit
模块访问您定义的函数,可以传递包含import
语句的setup参数:
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"))
Another option is to pass 另一个选项是将globals()
to the globals parameter, which will cause the code to be executed within your current global namespace. globals()
传递给globals参数,这将导致代码在当前全局命名空间中执行。This can be more convenient than individually specifying imports:这可能比单独指定导入更方便:
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()))