26.6. timeit
— Mesurer le temps d’exécution de fragments de code¶
Nouveau dans la version 2.3.
Code source : Lib/timeit.py
Ce module fournit une façon simple de mesurer le temps d’exécution de fragments de code Python. Il expose une Interface en ligne de commande ainsi qu’une interface Python. Ce module permet d’éviter un certain nombre de problèmes classiques liés à la mesure des temps d’exécution. Voir par exemple à ce sujet l’introduction par Tim Peters du chapitre « Algorithmes » dans le livre Python Cookbook, aux éditions O’Reilly.
26.6.1. Exemples simples¶
L’exemple suivant illustre l’utilisation de l”Interface en ligne de commande afin de comparer trois expressions différentes :
$ 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
L”Interface Python peut être utilisée aux mêmes fins avec :
>>> 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
Note however that timeit
will automatically determine the number of
repetitions only when the command-line interface is used. In the
Exemples section you can find more advanced examples.
26.6.2. Interface Python¶
Ce module définit une classe publique ainsi que trois fonctions destinées à simplifier son usage :
-
timeit.
timeit
(stmt='pass', setup='pass', timer=<default timer>, number=1000000)¶ Create a
Timer
instance with the given statement, setup code and timer function and run itstimeit()
method with number executions.Nouveau dans la version 2.6.
-
timeit.
repeat
(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)¶ Create a
Timer
instance with the given statement, setup code and timer function and run itsrepeat()
method with the given repeat count and number executions.Nouveau dans la version 2.6.
-
timeit.
default_timer
()¶ Define a default timer, in a platform-specific manner. On Windows,
time.clock()
has microsecond granularity, buttime.time()
”s granularity is 1/60th of a second. On Unix,time.clock()
has 1/100th of a second granularity, andtime.time()
is much more precise. On either platform,default_timer()
measures wall clock time, not the CPU time. This means that other processes running on the same computer may interfere with the timing.
-
class
timeit.
Timer
(stmt='pass', setup='pass', timer=<timer function>)¶ Classe permettant de mesurer le temps d’exécution de fragments de code.
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
timeit()
method. Therepeat()
method is a convenience to calltimeit()
multiple times and return a list of results.Modifié dans la version 2.6: The stmt and setup parameters can now also take objects that are callable without arguments. This will embed calls to them in a timer function that will then be executed by
timeit()
. Note that the timing overhead is a little larger in this case because of the extra function calls.-
timeit
(number=1000000)¶ Mesure le temps number exécution de l’instruction principale. Ceci exécute l’instruction de mise en place une seule fois puis renvoie un flottant correspondant au temps nécessaire à l’exécution de l’instruction principale à plusieurs reprises, mesuré en secondes. L’argument correspond au nombre d’itérations dans la boucle, par défaut un million. L’instruction principale, l’instruction de mise en place et la fonction de chronométrage utilisée sont passées au constructeur.
Note
By default,
timeit()
temporarily turns off 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 xrange(10): oct(i)', 'gc.enable()').timeit()
-
repeat
(repeat=3, number=1000000)¶ Appelle
timeit()
plusieurs fois.Cette fonction d’agrément appelle
timeit()
à plusieurs reprises et renvoie une liste de résultats. Le premier argument spécifie le nombre d’appels àtimeit()
. Le second argument spécifie l’argument number detimeit()
.Note
Il est tentant de vouloir calculer la moyenne et l’écart-type des résultats et notifier ces valeurs. Ce n’est cependant pas très utile. En pratique, la valeur la plus basse donne une estimation basse de la vitesse maximale à laquelle votre machine peut exécuter le fragment de code spécifié ; les valeurs hautes de la liste sont typiquement provoquées non pas par une variabilité de la vitesse d’exécution de Python, mais par d’autres processus interférant avec la précision du chronométrage. Le
min()
du résultat est probablement la seule valeur à laquelle vous devriez vous intéresser. Pour aller plus loin, vous devriez regarder l’intégralité des résultats et utiliser le bon sens plutôt que les statistiques.
-
print_exc
(file=None)¶ Helper to print a traceback from the timed code.
Usage typique :
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
.
-
26.6.3. Interface en ligne de commande¶
Lorsque le module est appelé comme un programme en ligne de commande, la syntaxe suivante est utilisée :
python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
Les options suivantes sont gérées :
-
-n
N
,
--number
=N
¶ nombre d’exécutions de l’instruction statement
-
-r
N
,
--repeat
=N
¶ how many times to repeat the timer (default 3)
-
-s
S
,
--setup
=S
¶ instruction exécutée une seule fois à l’initialisation (
pass
par défaut)
-
-t
,
--time
¶
use
time.time()
(default on all platforms but Windows)
-
-c
,
--clock
¶
use
time.clock()
(default on Windows)
-
-v
,
--verbose
¶
print raw timing results; repeat for more digits precision
-
-h
,
--help
¶
affiche un court message d’aide puis quitte
Une instruction sur plusieurs lignes peut être donnée en entrée en spécifiant chaque ligne comme un argument séparé. Indenter une ligne est possible en encadrant l’argument de guillemets et en le préfixant par des espaces. Plusieurs -s
sont gérées de la même façon.
Si -n
n’est pas donnée, le nombre de boucles adapté est déterminé automatiquement en essayant les puissances de 10 successives jusqu’à ce que le temps total d’exécution dépasse 0,2 secondes.
default_timer()
measurations 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 3 repetitions is probably enough in most cases. On
Unix, you can use time.clock()
to measure CPU time.
Note
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
baseline overhead can be measured by invoking the program without arguments, and
it might differ between Python versions. Also, to fairly compare older Python
versions to Python 2.3, you may want to use Python’s -O
option (see Optimizations) for
the older versions to avoid timing SET_LINENO
instructions.
26.6.4. Exemples¶
Il est possible de fournir une instruction de mise en place exécutée une seule fois au début du chronométrage :
$ 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
La même chose peut être réalisée en utilisant la classe Timer
et ses méthodes :
>>> 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]
Les exemples qui suivent montrent comment chronométrer des expressions sur plusieurs lignes. Nous comparons ici le coût d’utilisation de hasattr()
par rapport à try
/except
pour tester la présence ou l’absence d’attributs d’un objet :
$ 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
>>> # attribute is missing
>>> 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
>>>
>>> # attribute is present
>>> 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
Afin de permettre à timeit
d’accéder aux fonctions que vous avez définies, vous pouvez passer au paramètre setup une instruction d’importation:
def test():
"""Stupid test function"""
L = []
for i in range(100):
L.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))