mirror of https://github.com/python/cpython
#15979: merge with 3.2.
This commit is contained in:
commit
4443762bf5
|
@ -14,113 +14,154 @@
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
This module provides a simple way to time small bits of Python code. It has both
|
This module provides a simple way to time small bits of Python code. It has both
|
||||||
command line as well as callable interfaces. It avoids a number of common traps
|
a :ref:`command-line-interface` as well as a :ref:`callable <python-interface>`
|
||||||
for measuring execution times. See also Tim Peters' introduction to the
|
one. It avoids a number of common traps for measuring execution times.
|
||||||
"Algorithms" chapter in the Python Cookbook, published by O'Reilly.
|
See also Tim Peters' introduction to the "Algorithms" chapter in the *Python
|
||||||
|
Cookbook*, published by O'Reilly.
|
||||||
The module defines the following public class:
|
|
||||||
|
|
||||||
|
|
||||||
.. class:: Timer(stmt='pass', setup='pass', timer=<timer function>)
|
Basic Examples
|
||||||
|
--------------
|
||||||
|
|
||||||
Class for timing execution speed of small code snippets.
|
The following example shows how the :ref:`command-line-interface`
|
||||||
|
can be used to compare three different expressions:
|
||||||
|
|
||||||
The constructor takes a statement to be timed, an additional statement used for
|
.. code-block:: sh
|
||||||
setup, and a timer function. Both statements default to ``'pass'``; the timer
|
|
||||||
function is platform-dependent (see the module doc string). *stmt* and *setup*
|
|
||||||
may also contain multiple statements separated by ``;`` or newlines, as long as
|
|
||||||
they don't contain multi-line string literals.
|
|
||||||
|
|
||||||
To measure the execution time of the first statement, use the :meth:`Timer.timeit`
|
$ python -m timeit '"-".join(str(n) for n in range(100))'
|
||||||
method. The :meth:`repeat` method is a convenience to call :meth:`.timeit`
|
10000 loops, best of 3: 40.3 usec per loop
|
||||||
multiple times and return a list of results.
|
$ 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
|
||||||
|
|
||||||
The *stmt* and *setup* parameters can also take objects that are callable
|
This can be achieved from the :ref:`python-interface` with::
|
||||||
without arguments. This will embed calls to them in a timer function that
|
|
||||||
will then be executed by :meth:`.timeit`. Note that the timing overhead is a
|
>>> import timeit
|
||||||
little larger in this case because of the extra function calls.
|
>>> 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
|
||||||
|
|
||||||
|
Note however that :mod:`timeit` will automatically determine the number of
|
||||||
|
repetitions only when the command-line interface is used. In the
|
||||||
|
:ref:`timeit-examples` section you can find more advanced examples.
|
||||||
|
|
||||||
|
|
||||||
.. method:: Timer.print_exc(file=None)
|
.. _python-interface:
|
||||||
|
|
||||||
Helper to print a traceback from the timed code.
|
Python Interface
|
||||||
|
----------------
|
||||||
|
|
||||||
Typical use::
|
The module defines three convenience functions and a public class:
|
||||||
|
|
||||||
t = Timer(...) # outside the try/except
|
|
||||||
try:
|
|
||||||
t.timeit(...) # or t.repeat(...)
|
|
||||||
except:
|
|
||||||
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 ``sys.stderr``.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: Timer.repeat(repeat=3, number=1000000)
|
.. function:: timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
|
||||||
|
|
||||||
Call :meth:`.timeit` a few times.
|
Create a :class:`Timer` instance with the given statement, *setup* code and
|
||||||
|
*timer* function and run its :meth:`.timeit` method with *number* executions.
|
||||||
This is a convenience function that calls the :meth:`.timeit` repeatedly,
|
|
||||||
returning a list of results. The first argument specifies how many times to
|
|
||||||
call :meth:`.timeit`. The second argument specifies the *number* argument for
|
|
||||||
:meth:`.timeit`.
|
|
||||||
|
|
||||||
.. 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. So the :func:`min` of the result is probably the only number
|
|
||||||
you should be interested in. After that, you should look at the entire vector
|
|
||||||
and apply common sense rather than statistics.
|
|
||||||
|
|
||||||
|
|
||||||
.. method:: Timer.timeit(number=1000000)
|
.. function:: repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)
|
||||||
|
|
||||||
Time *number* executions of the main statement. This executes the setup
|
Create a :class:`Timer` instance with the given statement, *setup* code and
|
||||||
statement once, and then returns the time it takes to execute the main statement
|
*timer* function and run its :meth:`.repeat` method with the given *repeat*
|
||||||
a number of times, measured in seconds as a float. The argument is the number
|
count and *number* executions.
|
||||||
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.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
By default, :meth:`.timeit` temporarily turns off :term:`garbage collection`
|
|
||||||
during the timing. The advantage of this approach is that it makes
|
|
||||||
independent timings more comparable. This disadvantage is that GC may be
|
|
||||||
an important component of the performance of the function being measured.
|
|
||||||
If so, GC can be re-enabled as the first statement in the *setup* string.
|
|
||||||
For example::
|
|
||||||
|
|
||||||
timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
|
|
||||||
|
|
||||||
|
|
||||||
The module also defines three convenience functions:
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: default_timer()
|
.. function:: default_timer()
|
||||||
|
|
||||||
The default timer, which is always :func:`time.perf_counter`.
|
The default timer, which is always :func:`time.perf_counter`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
.. function:: repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)
|
:func:`time.perf_counter` is now the default timer.
|
||||||
|
|
||||||
Create a :class:`Timer` instance with the given statement, setup code and timer
|
|
||||||
function and run its :meth:`repeat` method with the given repeat count and
|
|
||||||
*number* executions.
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
|
.. class:: Timer(stmt='pass', setup='pass', timer=<timer function>)
|
||||||
|
|
||||||
Create a :class:`Timer` instance with the given statement, setup code and timer
|
Class for timing execution speed of small code snippets.
|
||||||
function and run its :meth:`.timeit` method with *number* executions.
|
|
||||||
|
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).
|
||||||
|
*stmt* and *setup* may also contain multiple statements separated by ``;``
|
||||||
|
or newlines, as long as they don't contain multi-line string literals.
|
||||||
|
|
||||||
|
To measure the execution time of the first statement, use the :meth:`.timeit`
|
||||||
|
method. The :meth:`.repeat` method is a convenience to call :meth:`.timeit`
|
||||||
|
multiple times and return a list of results.
|
||||||
|
|
||||||
|
The *stmt* and *setup* parameters can also take objects that are callable
|
||||||
|
without arguments. This will embed calls to them in a timer function that
|
||||||
|
will then be executed by :meth:`.timeit`. Note that the timing overhead is a
|
||||||
|
little larger in this case because of the extra function calls.
|
||||||
|
|
||||||
|
|
||||||
Command Line Interface
|
.. method:: Timer.timeit(number=1000000)
|
||||||
|
|
||||||
|
Time *number* executions of the main statement. 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.
|
||||||
|
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.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
By default, :meth:`.timeit` temporarily turns off :term:`garbage
|
||||||
|
collection` during the timing. The advantage of this approach is that
|
||||||
|
it makes independent timings more comparable. This disadvantage is
|
||||||
|
that GC may be an important component of the performance of the
|
||||||
|
function being measured. If so, GC can be re-enabled as the first
|
||||||
|
statement in the *setup* string. For example::
|
||||||
|
|
||||||
|
timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Timer.repeat(repeat=3, number=1000000)
|
||||||
|
|
||||||
|
Call :meth:`.timeit` a few times.
|
||||||
|
|
||||||
|
This is a convenience function that calls the :meth:`.timeit` repeatedly,
|
||||||
|
returning a list of results. The first argument specifies how many times
|
||||||
|
to call :meth:`.timeit`. The second argument specifies the *number*
|
||||||
|
argument for :meth:`.timeit`.
|
||||||
|
|
||||||
|
.. 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.
|
||||||
|
So the :func:`min` of the result is probably the only number you
|
||||||
|
should be interested in. After that, you should look at the entire
|
||||||
|
vector and apply common sense rather than statistics.
|
||||||
|
|
||||||
|
|
||||||
|
.. method:: Timer.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:
|
||||||
|
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 :data:`sys.stderr`.
|
||||||
|
|
||||||
|
|
||||||
|
.. _command-line-interface:
|
||||||
|
|
||||||
|
Command-Line Interface
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
When called as a program from the command line, the following form is used::
|
When called as a program from the command line, the following form is used::
|
||||||
|
@ -184,25 +225,53 @@ most cases. You can use :func:`time.process_time` to measure CPU time.
|
||||||
|
|
||||||
There is a certain baseline overhead associated with executing a pass statement.
|
There is a certain baseline overhead associated with executing a pass statement.
|
||||||
The code here doesn't try to hide it, but you should be aware of it. The
|
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.
|
baseline overhead can be measured by invoking the program without arguments,
|
||||||
|
and it might differ between Python versions.
|
||||||
|
|
||||||
The baseline overhead differs between Python versions! Also, to fairly compare
|
|
||||||
older Python versions to Python 2.3, you may want to use Python's :option:`-O`
|
|
||||||
option for the older versions to avoid timing ``SET_LINENO`` instructions.
|
|
||||||
|
|
||||||
|
.. _timeit-examples:
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Here are two example sessions (one using the command line, one using the module
|
It is possible to provide a setup statement that is executed only once at the beginning:
|
||||||
interface) that compare the cost of using :func:`hasattr` vs.
|
|
||||||
:keyword:`try`/:keyword:`except` to test for missing and present object
|
.. code-block:: sh
|
||||||
attributes. ::
|
|
||||||
|
$ 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
|
||||||
|
|
||||||
|
The same can be done using the :class:`Timer` class and its methods::
|
||||||
|
|
||||||
|
>>> 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]
|
||||||
|
|
||||||
|
|
||||||
|
The following examples show how to time expressions that contain multiple lines.
|
||||||
|
Here we compare the cost of using :func:`hasattr` vs. :keyword:`try`/:keyword:`except`
|
||||||
|
to test for missing and present object attributes:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
$ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass'
|
$ python -m timeit 'try:' ' str.__bool__' 'except AttributeError:' ' pass'
|
||||||
100000 loops, best of 3: 15.7 usec per loop
|
100000 loops, best of 3: 15.7 usec per loop
|
||||||
$ python -m timeit 'if hasattr(str, "__bool__"): pass'
|
$ python -m timeit 'if hasattr(str, "__bool__"): pass'
|
||||||
100000 loops, best of 3: 4.26 usec per loop
|
100000 loops, best of 3: 4.26 usec per loop
|
||||||
|
|
||||||
$ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass'
|
$ python -m timeit 'try:' ' int.__bool__' 'except AttributeError:' ' pass'
|
||||||
1000000 loops, best of 3: 1.43 usec per loop
|
1000000 loops, best of 3: 1.43 usec per loop
|
||||||
$ python -m timeit 'if hasattr(int, "__bool__"): pass'
|
$ python -m timeit 'if hasattr(int, "__bool__"): pass'
|
||||||
|
@ -211,36 +280,32 @@ attributes. ::
|
||||||
::
|
::
|
||||||
|
|
||||||
>>> import timeit
|
>>> import timeit
|
||||||
|
>>> # attribute is missing
|
||||||
>>> s = """\
|
>>> s = """\
|
||||||
... try:
|
... try:
|
||||||
... str.__bool__
|
... str.__bool__
|
||||||
... except AttributeError:
|
... except AttributeError:
|
||||||
... pass
|
... pass
|
||||||
... """
|
... """
|
||||||
>>> t = timeit.Timer(stmt=s)
|
>>> timeit.timeit(stmt=s, number=100000)
|
||||||
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
|
0.9138244460009446
|
||||||
17.09 usec/pass
|
>>> s = "if hasattr(str, '__bool__'): pass"
|
||||||
>>> s = """\
|
>>> timeit.timeit(stmt=s, number=100000)
|
||||||
... if hasattr(str, '__bool__'): pass
|
0.5829014980008651
|
||||||
... """
|
>>>
|
||||||
>>> t = timeit.Timer(stmt=s)
|
>>> # attribute is present
|
||||||
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
|
|
||||||
4.85 usec/pass
|
|
||||||
>>> s = """\
|
>>> s = """\
|
||||||
... try:
|
... try:
|
||||||
... int.__bool__
|
... int.__bool__
|
||||||
... except AttributeError:
|
... except AttributeError:
|
||||||
... pass
|
... pass
|
||||||
... """
|
... """
|
||||||
>>> t = timeit.Timer(stmt=s)
|
>>> timeit.timeit(stmt=s, number=100000)
|
||||||
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
|
0.04215312199994514
|
||||||
1.97 usec/pass
|
>>> s = "if hasattr(int, '__bool__'): pass"
|
||||||
>>> s = """\
|
>>> timeit.timeit(stmt=s, number=100000)
|
||||||
... if hasattr(int, '__bool__'): pass
|
0.08588060699912603
|
||||||
... """
|
|
||||||
>>> t = timeit.Timer(stmt=s)
|
|
||||||
>>> print("%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000))
|
|
||||||
3.15 usec/pass
|
|
||||||
|
|
||||||
To give the :mod:`timeit` module access to functions you define, you can pass a
|
To give the :mod:`timeit` module access to functions you define, you can pass a
|
||||||
*setup* parameter which contains an import statement::
|
*setup* parameter which contains an import statement::
|
||||||
|
@ -250,7 +315,5 @@ To give the :mod:`timeit` module access to functions you define, you can pass a
|
||||||
L = [i for i in range(100)]
|
L = [i for i in range(100)]
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
from timeit import Timer
|
import timeit
|
||||||
t = Timer("test()", "from __main__ import test")
|
print(timeit.timeit("test()", setup="from __main__ import test"))
|
||||||
print(t.timeit())
|
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,8 @@ Documentation
|
||||||
- Issue #15533: Clarify docs and add tests for `subprocess.Popen()`'s cwd
|
- Issue #15533: Clarify docs and add tests for `subprocess.Popen()`'s cwd
|
||||||
argument.
|
argument.
|
||||||
|
|
||||||
|
- Issue #15979: Improve timeit documentation.
|
||||||
|
|
||||||
- Issue #16036: Improve documentation of built-in `int()`'s signature and
|
- Issue #16036: Improve documentation of built-in `int()`'s signature and
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue