Comment mesurer le temps écoulé en Python?


1212

Ce que je veux, c'est commencer à compter le temps quelque part dans mon code, puis obtenir le temps écoulé, pour mesurer le temps qu'il a fallu pour exécuter quelques fonctions. Je pense que j'utilise mal le module timeit, mais les documents sont juste déroutants pour moi.

import timeit

start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)

Réponses:


1457

Si vous souhaitez simplement mesurer le temps écoulé de l'horloge murale entre deux points, vous pouvez utiliser time.time():

import time

start = time.time()
print("hello")
end = time.time()
print(end - start)

Cela donne le temps d'exécution en secondes.

Une autre option depuis 3.3 pourrait être d'utiliser perf_counterou process_time, selon vos besoins. Avant la 3.3, il était recommandé d'utiliser time.clock(merci Amber ). Cependant, il est actuellement obsolète:

Sous Unix, renvoyez le temps processeur actuel sous la forme d'un nombre à virgule flottante exprimé en secondes. La précision, et en fait la définition même de la signification du «temps processeur», dépend de celle de la fonction C du même nom.

Sous Windows, cette fonction renvoie les secondes de l'horloge murale écoulées depuis le premier appel à cette fonction, sous la forme d'un nombre à virgule flottante, basé sur la fonction Win32 QueryPerformanceCounter(). La résolution est généralement meilleure qu'une microseconde.

Déconseillé depuis la version 3.3 : Le comportement de cette fonction dépend de la plateforme: utilisez perf_counter()ou à la process_time()place , selon vos besoins, pour avoir un comportement bien défini.


17
et pour les microsecondes, utilisez datetime.time ()
Inca

111
(Pour la mesure des performances, time.clock()est en fait préférable, car il ne peut pas être perturbé si l'horloge système est gâchée, mais .time()accomplit principalement le même objectif.)
Amber

4
Je pense que python -mtimeit est bien meilleur car il s'exécute plus souvent et il est construit comme un moyen natif de mesurer le temps en python
Visgean Skeloru

4
Existe-t-il un bon moyen de convertir le temps d'execturion résultant en secondes en quelque chose comme HH: MM :: SS?
Danijel

12
@Danijel: print(timedelta(seconds=execution_time)). Bien que ce soit une question distincte.
jfs

689

Utilisez timeit.default_timerau lieu de timeit.timeit. Le premier fournit automatiquement la meilleure horloge disponible sur votre plateforme et version de Python:

from timeit import default_timer as timer

start = timer()
# ...
end = timer()
print(end - start) # Time in seconds, e.g. 5.38091952400282

timeit.default_timer est affecté à time.time () ou time.clock () selon le système d'exploitation. Sur Python 3.3+, default_timer est time.perf_counter () sur toutes les plateformes. Voir Python - time.clock () contre time.time () - précision?

Voir également:


29
Excellente réponse - l'utilisation de timeit produira des résultats beaucoup plus précis car il tiendra automatiquement compte de choses comme la collecte des ordures et les différences de système d'exploitation
lkgarrison

1
Cela donne du temps en ms ou en secondes?
Katie

3
@KhushbooTiwari en quelques fractions de seconde.
jfs

5
Je pense que cette note de la documentation officielle doit être ajoutéedefault_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.
KGS

1
@KGS: La mesure des performances est très délicate de manière subtile (il est facile de se tromper). Il y a beaucoup d'autres remarques qui pourraient être pertinentes ici. Suivez les liens dans la réponse. Vous pourriez également être intéressé par le perfmodule (inexistant au moment de la réponse) qui fournit la même interface, mais il rend parfois différent des timeitdécisions du module sur la façon de mesurer les performances temporelles.
jfs

129

Python 3 uniquement:

Étant donné que time.clock () est obsolète à partir de Python 3.3 , vous voudrez l'utiliser time.perf_counter()pour la synchronisation à l'échelle du système ou time.process_time()pour la synchronisation à l'échelle du processus, exactement comme vous l' utilisiez auparavant time.clock():

import time

t = time.process_time()
#do some stuff
elapsed_time = time.process_time() - t

La nouvelle fonction process_timen'inclura pas le temps écoulé pendant le sommeil.


28
Utiliseztimeit.default_timer au lieu de time.perf_counter. Le premier choisira la minuterie appropriée pour mesurer les performances temporelles réglées pour votre plate-forme et votre version Python. process_time()n'inclut pas le temps de sommeil et il n'est donc pas approprié de mesurer le temps écoulé.
jfs

2
J'utilise l'implémentation suggérée par Pierre, les valeurs sont-elles données en secondes?
ugotchi

Cette réponse semble hors sujet (enfin, la question n'était pas très précise). Il existe deux mesures de «temps»: le temps d'horloge murale entre deux points, de la consommation de processeurs du processus.
Franklin Piat

87

Étant donné une fonction que vous souhaitez chronométrer,

test.py:

def foo(): 
    # print "hello"   
    return "hello"

le moyen le plus simple à utiliser timeitest de l'appeler à partir de la ligne de commande:

% python -mtimeit -s'import test' 'test.foo()'
1000000 loops, best of 3: 0.254 usec per loop

N'essayez pas d'utiliser time.timeou time.clock(naïvement) de comparer la vitesse des fonctions. Ils peuvent donner des résultats trompeurs .

PS. Ne placez pas d'instructions d'impression dans une fonction que vous souhaitez chronométrer; sinon le temps mesuré dépendra de la vitesse du terminal .


65

C'est amusant de le faire avec un gestionnaire de contexte qui se souvient automatiquement de l'heure de début lors de l'entrée dans un withbloc, puis fige l'heure de fin à la sortie du bloc. Avec une petite ruse, vous pouvez même obtenir un décompte du temps écoulé à l'intérieur du bloc à partir de la même fonction de gestionnaire de contexte.

La bibliothèque principale n'en a pas (mais devrait probablement l'être). Une fois en place, vous pouvez faire des choses comme:

with elapsed_timer() as elapsed:
    # some lengthy code
    print( "midpoint at %.2f seconds" % elapsed() )  # time so far
    # other lengthy code

print( "all done at %.2f seconds" % elapsed() )

Voici le code du gestionnaire de contexte suffisant pour faire l'affaire:

from contextlib import contextmanager
from timeit import default_timer

@contextmanager
def elapsed_timer():
    start = default_timer()
    elapser = lambda: default_timer() - start
    yield lambda: elapser()
    end = default_timer()
    elapser = lambda: end-start

Et un code de démonstration exécutable:

import time

with elapsed_timer() as elapsed:
    time.sleep(1)
    print(elapsed())
    time.sleep(2)
    print(elapsed())
    time.sleep(3)

Notez que par conception de cette fonction, la valeur de retour de elapsed()est gelée à la sortie du bloc et les appels suivants renvoient la même durée (d'environ 6 secondes dans cet exemple de jouet).


2
Autre exemple de gestionnaire de contexte: dabeaz.blogspot.fr/2010/02/…
Jérôme

1
@ Jérôme bel exemple - je l'ai adapté comme une autre réponse - stackoverflow.com/a/41408510/243392
Brian Burns

62

Temps de mesure en secondes:

from timeit import default_timer as timer
from datetime import timedelta

start = timer()
end = timer()
print(timedelta(seconds=end-start))

Sortie :

0:00:01.946339

1
C'est la réponse la plus concise avec la sortie la plus propre.
Dave Liu

56

Je préfère ça. timeitdoc est beaucoup trop déroutant.

from datetime import datetime 

start_time = datetime.now() 

# INSERT YOUR CODE 

time_elapsed = datetime.now() - start_time 

print('Time elapsed (hh:mm:ss.ms) {}'.format(time_elapsed))

Notez qu'il n'y a pas de mise en forme ici, je viens d'écrire hh:mm:ssdans l'impression pour que l'on puisse interprétertime_elapsed


On m'a dit que timeit calcule le temps CPU, datetime prend-il également en compte le temps CPU utilisé? Est-ce la même chose?
Sreehari R

3
Il est risqué de mesurer le temps écoulé de cette façon car datetime.now () peut changer entre les deux appels pour des raisons telles que la synchronisation de l'heure du réseau, le passage à l'heure d'été ou l'utilisateur qui tourne l'horloge.
user1318499

45

Voici une autre façon de procéder:

>> from pytictoc import TicToc
>> t = TicToc() # create TicToc instance
>> t.tic() # Start timer
>> # do something
>> t.toc() # Print elapsed time
Elapsed time is 2.612231 seconds.

Comparé à la manière traditionnelle:

>> from time import time
>> t1 = time()
>> # do something
>> t2 = time()
>> elapsed = t2 - t1
>> print('Elapsed time is %f seconds.' % elapsed)
Elapsed time is 2.612231 seconds.

Installation:

pip install pytictoc

Reportez-vous à la page PyPi pour plus de détails.


13
Il serait bon d'expliquer l'avantage d'utiliser cette bibliothèque par rapport à d'autres approches.
hlg

La fonctionnalité imbriquée est en fait rompue. J'ai ouvert un problème décrivant où se trouve le problème dans le code, mais le dépôt n'a pas été maintenu depuis un an, donc je ne m'attendrais pas à un changement.
PetarMI

Je trouve la nidification un peu déroutante. Si je tombais t.tic()enterré dans le code, c'est à moi le développeur de garder une liste mentale de l'endroit dans la série où je devrais m'attendre à ce que ce soit. Vous trouvez-vous en train de créer des nids ou simplement plusieurs tictocs?
ScottieB

1
@PetarMI: Pour info, je viens de résoudre le problème avec ttictoc. Un vrai bordel que j'avais, mais ça devrait être bien maintenant.
H. Sánchez

33

Voici mes conclusions après avoir parcouru de nombreuses bonnes réponses ici ainsi que quelques autres articles.

Premièrement, si vous discutez entre timeitet time.time, le timeita deux avantages:

  1. timeit sélectionne la meilleure minuterie disponible sur votre version OS et Python.
  2. timeit désactive la collecte des ordures, cependant, ce n'est pas quelque chose que vous pouvez ou ne voulez pas.

Maintenant, le problème n'est timeitpas aussi simple à utiliser, car il nécessite une configuration et les choses deviennent laides lorsque vous avez un tas d'importations. Idéalement, vous voulez juste un décorateur ou utiliser un withbloc et mesurer le temps. Malheureusement, il n'y a rien de intégré disponible pour cela, vous avez donc deux options:

Option 1: utiliser la bibliothèque timebudget

Le timebudget est une bibliothèque polyvalente et très simple que vous pouvez utiliser en une seule ligne de code après l'installation de pip.

@timebudget  # Record how long this function takes
def my_method():
    # my code

Option 2: utiliser directement le module de code

J'ai créé ci-dessous un petit module utilitaire.

# utils.py
from functools import wraps
import gc
import timeit

def MeasureTime(f, no_print=False, disable_gc=False):
    @wraps(f)
    def _wrapper(*args, **kwargs):
        gcold = gc.isenabled()
        if disable_gc:
            gc.disable()
        start_time = timeit.default_timer()
        try:
            result = f(*args, **kwargs)
        finally:
            elapsed = timeit.default_timer() - start_time
            if disable_gc and gcold:
                gc.enable()
            if not no_print:
                print('"{}": {}s'.format(f.__name__, elapsed))
        return result
    return _wrapper

class MeasureBlockTime:
    def __init__(self,name="(block)", no_print=False, disable_gc=False):
        self.name = name
        self.no_print = no_print
        self.disable_gc = disable_gc
    def __enter__(self):
        self.gcold = gc.isenabled()
        if self.disable_gc:
            gc.disable()
        self.start_time = timeit.default_timer()
    def __exit__(self,ty,val,tb):
        self.elapsed = timeit.default_timer() - self.start_time
        if self.disable_gc and self.gcold:
            gc.enable()
        if not self.no_print:
            print('Function "{}": {}s'.format(self.name, self.elapsed))
        return False #re-raise any exceptions

Vous pouvez maintenant chronométrer n'importe quelle fonction simplement en plaçant un décorateur devant:

import utils

@utils.MeasureTime
def MyBigFunc():
    #do something time consuming
    for i in range(10000):
        print(i)

Si vous voulez chronométrer une partie du code, mettez-le simplement dans le withbloc:

import utils

#somewhere in my code

with utils.MeasureBlockTime("MyBlock"):
    #do something time consuming
    for i in range(10000):
        print(i)

# rest of my code

Avantages:

Il existe plusieurs versions à moitié sauvegardées, je tiens donc à souligner quelques points saillants:

  1. Utilisez la minuterie de timeit au lieu de time.time pour les raisons décrites précédemment.
  2. Vous pouvez désactiver GC pendant le chronométrage si vous le souhaitez.
  3. Decorator accepte les fonctions avec des paramètres nommés ou non.
  4. Possibilité de désactiver l'impression en mode bloc (utiliser with utils.MeasureBlockTime() as tpuis t.elapsed).
  5. Possibilité de garder gc activé pour le chronométrage des blocs.

28

Utiliser time.timepour mesurer l'exécution vous donne le temps d'exécution global de vos commandes, y compris le temps d'exécution passé par d'autres processus sur votre ordinateur. C'est le moment que l'utilisateur remarque, mais ce n'est pas bien si vous voulez comparer différents extraits de code / algorithmes / fonctions / ...

Plus d'informations sur timeit:

Si vous souhaitez un aperçu plus approfondi du profilage:

Mise à jour : J'ai beaucoup utilisé http://pythonhosted.org/line_profiler/ au cours de l'année dernière et je le trouve très utile et je recommande de l'utiliser à la place du module de profil Pythons.


19

Voici une petite classe de minuteur qui renvoie la chaîne "hh: mm: ss":

class Timer:
  def __init__(self):
    self.start = time.time()

  def restart(self):
    self.start = time.time()

  def get_time_hhmmss(self):
    end = time.time()
    m, s = divmod(end - self.start, 60)
    h, m = divmod(m, 60)
    time_str = "%02d:%02d:%02d" % (h, m, s)
    return time_str

Usage:

# Start timer
my_timer = Timer()

# ... do something

# Get time string:
time_hhmmss = my_timer.get_time_hhmmss()
print("Time elapsed: %s" % time_hhmmss )

# ... use the timer again
my_timer.restart()

# ... do something

# Get time:
time_hhmmss = my_timer.get_time_hhmmss()

# ... etc

17

Les modules python cProfile et pstats offrent un excellent support pour mesurer le temps écoulé dans certaines fonctions sans avoir à ajouter de code autour des fonctions existantes.

Par exemple, si vous avez un script python timeFunctions.py:

import time

def hello():
    print "Hello :)"
    time.sleep(0.1)

def thankyou():
    print "Thank you!"
    time.sleep(0.05)

for idx in range(10):
    hello()

for idx in range(100):
    thankyou()

Pour exécuter le profileur et générer des statistiques pour le fichier, vous pouvez simplement exécuter:

python -m cProfile -o timeStats.profile timeFunctions.py

Cela consiste à utiliser le module cProfile pour profiler toutes les fonctions dans timeFunctions.py et à collecter les statistiques dans le fichier timeStats.profile. Notez que nous n'avons pas eu à ajouter de code au module existant (timeFunctions.py) et cela peut être fait avec n'importe quel module.

Une fois que vous avez le fichier stats, vous pouvez exécuter le module pstats comme suit:

python -m pstats timeStats.profile

Cela exécute le navigateur de statistiques interactif qui vous offre de nombreuses fonctionnalités intéressantes. Pour votre cas d'utilisation particulier, vous pouvez simplement vérifier les statistiques de votre fonction. Dans notre exemple, la vérification des statistiques pour les deux fonctions nous montre ce qui suit:

Welcome to the profile statistics browser.
timeStats.profile% stats hello
<timestamp>    timeStats.profile

         224 function calls in 6.014 seconds

   Random listing order was used
   List reduced from 6 to 1 due to restriction <'hello'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10    0.000    0.000    1.001    0.100 timeFunctions.py:3(hello)

timeStats.profile% stats thankyou
<timestamp>    timeStats.profile

         224 function calls in 6.014 seconds

   Random listing order was used
   List reduced from 6 to 1 due to restriction <'thankyou'>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      100    0.002    0.000    5.012    0.050 timeFunctions.py:7(thankyou)

L'exemple factice ne fait pas grand-chose mais vous donne une idée de ce qui peut être fait. La meilleure partie de cette approche est que je n'ai pas à modifier le code existant pour obtenir ces numéros et, bien entendu, aider au profilage.


Tout cela est bien, mais AFAICT mesure toujours le temps CPU, pas le temps d'horloge murale.
ShreevatsaR

1
En fait, il y a une certaine confusion; il semble que cProfile regarde l'heure d'horloge murale par défaut. J'ai voté pour votre réponse.
ShreevatsaR

FYI: Si vous obtenez python -m pstats timeStats.profile ValueError: bad marshal data (unknown type code)vérifier votre version de python que vous utilisez. Je l'ai eu quand j'ai couru python3 -m cProfile...et python -m pstats. Mon erreur, mais m'a eu une seconde, alors je voulais partager don't forget consistency. =)
JayRizzo

17

Voici un autre gestionnaire de contexte pour le code de synchronisation -

Usage:

from benchmark import benchmark

with benchmark("Test 1+1"):
    1+1
=>
Test 1+1 : 1.41e-06 seconds

ou, si vous avez besoin de la valeur de temps

with benchmark("Test 1+1") as b:
    1+1
print(b.time)
=>
Test 1+1 : 7.05e-07 seconds
7.05233786763e-07

benchmark.py :

from timeit import default_timer as timer

class benchmark(object):

    def __init__(self, msg, fmt="%0.3g"):
        self.msg = msg
        self.fmt = fmt

    def __enter__(self):
        self.start = timer()
        return self

    def __exit__(self, *args):
        t = timer() - self.start
        print(("%s : " + self.fmt + " seconds") % (self.msg, t))
        self.time = t

Adapté de http://dabeaz.blogspot.fr/2010/02/context-manager-for-timing-benchmarks.html


17

Utilisez le module de profileur. Il donne un profil très détaillé.

import profile
profile.run('main()')

il produit quelque chose comme:

          5 function calls in 0.047 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 :0(exec)
        1    0.047    0.047    0.047    0.047 :0(setprofile)
        1    0.000    0.000    0.000    0.000 <string>:1(<module>)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    0.047    0.047 profile:0(main())
        1    0.000    0.000    0.000    0.000 two_sum.py:2(twoSum)

Je l'ai trouvé très instructif.


1
Qu'est-ce que c'est main()? Serait plus utile si vous pouviez fournir un exemple de code simple.
not2qubit

15

Je l'aime simple (python 3):

from timeit import timeit

timeit(lambda: print("hello"))

La sortie est en microsecondes pour une seule exécution:

2.430883963010274

Explication : timeit exécute la fonction anonyme 1 million de fois par défaut et le résultat est donné en secondes . Par conséquent, le résultat pour une seule exécution est le même, mais en microsecondes en moyenne.


Pour les opérations lentes , ajoutez un nombre d'itérations inférieur ou vous pourriez attendre indéfiniment:

import time

timeit(lambda: time.sleep(1.5), number=1)

La sortie est toujours en secondes pour le nombre total d'itérations:

1.5015795179999714

14

(Avec Ipython uniquement), vous pouvez utiliser % timeit pour mesurer le temps de traitement moyen:

def foo():
    print "hello"

et alors:

%timeit foo()

le résultat est quelque chose comme:

10000 loops, best of 3: 27 µs per loop

4
Il convient de mentionner qu'il est possible de passer des drapeaux à% timeit, par exemple -n spécifie combien de fois le code doit être répété.
raacer

11

Une autre façon d'utiliser timeit :

from timeit import timeit

def func():
    return 1 + 1

time = timeit(func, number=1)
print(time)

10

sur python3:

from time import sleep, perf_counter as pc
t0 = pc()
sleep(1)
print(pc()-t0)

élégant et court.


Qu'est-ce que c'est? SP?
KIC

@KIC C'est en quelques secondes.
Guimoute il y a

9

Une sorte de réponse super tardive, mais peut-être qu'elle sert un but à quelqu'un. C'est une façon de faire qui je pense est super propre.

import time

def timed(fun, *args):
    s = time.time()
    r = fun(*args)
    print('{} execution took {} seconds.'.format(fun.__name__, time.time()-s))
    return(r)

timed(print, "Hello")

Gardez à l'esprit que "print" est une fonction de Python 3 et non de Python 2.7. Cependant, cela fonctionne avec toute autre fonction. À votre santé!


Comment imprimer très peu de fois? Je reçois toujours 0.0sec toujours
Rowland Mtetezi

Vous pouvez en faire un décorateur; cela me semble encore mieux.
Daniel Moskovich

8

Vous pouvez utiliser timeit.

Voici un exemple sur la façon de tester naive_func qui prend un paramètre à l'aide de Python REPL:

>>> import timeit                                                                                         

>>> def naive_func(x):                                                                                    
...     a = 0                                                                                             
...     for i in range(a):                                                                                
...         a += i                                                                                        
...     return a                                                                                          

>>> def wrapper(func, *args, **kwargs):                                                                   
...     def wrapper():                                                                                    
...         return func(*args, **kwargs)                                                                  
...     return wrapper                                                                                    

>>> wrapped = wrapper(naive_func, 1_000)                                                                  

>>> timeit.timeit(wrapped, number=1_000_000)                                                              
0.4458435332577161  

Vous n'avez pas besoin de la fonction wrapper si la fonction n'a pas de paramètres.


1
Un lambdaserait plus succinct:print(timeit.timeit(lambda: naive_func(1_000), number=1_000_000))
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

7

Nous pouvons également convertir le temps en temps lisible par l'homme.

import time, datetime

start = time.clock()

def num_multi1(max):
    result = 0
    for num in range(0, 1000):
        if (num % 3 == 0 or num % 5 == 0):
            result += num

    print "Sum is %d " % result

num_multi1(1000)

end = time.clock()
value = end - start
timestamp = datetime.datetime.fromtimestamp(value)
print timestamp.strftime('%Y-%m-%d %H:%M:%S')

6

J'ai fait une bibliothèque pour ça, si vous voulez mesurer une fonction vous pouvez le faire comme ça


from pythonbenchmark import compare, measure
import time

a,b,c,d,e = 10,10,10,10,10
something = [a,b,c,d,e]

@measure
def myFunction(something):
    time.sleep(0.4)

@measure
def myOptimizedFunction(something):
    time.sleep(0.2)

myFunction(input)
myOptimizedFunction(input)

https://github.com/Karlheinzniebuhr/pythonbenchmark


6

Pour obtenir un aperçu récursif de chaque appel de fonction, procédez comme suit:

%load_ext snakeviz
%%snakeviz

Il prend juste ces 2 lignes de code dans un cahier Jupyter , et il génère un joli diagramme interactif. Par exemple:

entrez la description de l'image ici

Voici le code. Encore une fois, les 2 lignes commençant par %sont les seules lignes de code supplémentaires nécessaires pour utiliser snakeviz:

# !pip install snakeviz
%load_ext snakeviz
import glob
import hashlib

%%snakeviz

files = glob.glob('*.txt')
def print_files_hashed(files):
    for file in files:
        with open(file) as f:
            print(hashlib.md5(f.read().encode('utf-8')).hexdigest())
print_files_hashed(files)

Il semble également possible d'exécuter snakeviz en dehors des blocs-notes. Plus d'informations sur le site snakeviz .


2
import time

def getElapsedTime(startTime, units):
    elapsedInSeconds = time.time() - startTime
    if units == 'sec':
        return elapsedInSeconds
    if units == 'min':
        return elapsedInSeconds/60
    if units == 'hour':
        return elapsedInSeconds/(60*60)

2

Cette approche unique basée sur les classes offre une représentation de chaîne imprimable, un arrondi personnalisable et un accès pratique au temps écoulé sous forme de chaîne ou de flottant. Il a été développé avec Python 3.7.

import datetime
import timeit


class Timer:
    """Measure time used."""
    # Ref: https://stackoverflow.com/a/57931660/

    def __init__(self, round_ndigits: int = 0):
        self._round_ndigits = round_ndigits
        self._start_time = timeit.default_timer()

    def __call__(self) -> float:
        return timeit.default_timer() - self._start_time

    def __str__(self) -> str:
        return str(datetime.timedelta(seconds=round(self(), self._round_ndigits)))

Usage:

# Setup timer
>>> timer = Timer()

# Access as a string
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:03.
>>> print(f'Time elapsed is {timer}.')
Time elapsed is 0:00:04.

# Access as a float
>>> timer()
6.841332235
>>> timer()
7.970274425

1

Mesurer le temps d'exécution de petits extraits de code.

Unité de temps : mesurée en secondes sous forme de flotteur

import timeit
t = timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))')
t.timeit()
t.repeat()
>[1.2934070999999676, 1.3335035000000062, 1.422568500000125]

La méthode repeat () est pratique pour appeler plusieurs fois timeit () et renvoyer une liste de résultats.

repeat(repeat=3

Avec cette liste, nous pouvons prendre une moyenne de tous les temps.

Par défaut, timeit () désactive temporairement la récupération de place pendant le chronométrage. time.Timer () résout ce problème.

Avantages:

timeit.Timer () rend les timings indépendants plus comparables. La gc peut être un élément important de la performance de la fonction mesurée. Si c'est le cas, gc (garbage collector) peut être réactivé comme première instruction de la chaîne de configuration. Par exemple:

timeit.Timer('li = list(map(lambda x:x*2,[1,2,3,4,5]))',setup='gc.enable()')

Source Python Docs !


1

Si vous voulez pouvoir chronométrer les fonctions facilement, vous pouvez utiliser un simple décorateur:

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        original_return_val = func(*args, **kwargs)
        end = time.time()
        print("time elapsed in ", func.__name__, ": ", end - start, sep='')
        return original_return_val

    return wrapper

Vous pouvez l'utiliser sur une fonction que vous souhaitez chronométrer comme ceci:

@timing_decorator
def function_to_time():
    time.sleep(1)

Ensuite, chaque fois que vous appelez function_to_time, il imprimera le temps nécessaire et le nom de la fonction à chronométrer.


1

basé sur la solution contextmanager proposée par https://stackoverflow.com/a/30024601/5095636 , ci-dessous la version gratuite de lambda, car flake8 met en garde contre l'utilisation de lambda selon E731 :

from contextlib import contextmanager
from timeit import default_timer

@contextmanager
def elapsed_timer():
    start_time = default_timer()

    class _Timer():
      start = start_time
      end = default_timer()
      duration = end - start

    yield _Timer

    end_time = default_timer()
    _Timer.end = end_time
    _Timer.duration = end_time - start_time

tester:

from time import sleep

with elapsed_timer() as t:
    print("start:", t.start)
    sleep(1)
    print("end:", t.end)

t.start
t.end
t.duration

1

La façon la plus simple de calculer la durée d'une opération:

import time

start_time = time.time()
print(time.ctime())

<operations, programs>

print('minutes: ',(time.time() - start_time)/60)

1

Voici un décorateur assez bien documenté et entièrement typé que j'utilise comme utilitaire général:

from functools import wraps
from time import perf_counter
from typing import Any, Callable, Optional, TypeVar, cast

F = TypeVar("F", bound=Callable[..., Any])


def timer(prefix: Optional[str] = None, precision: int = 6) -> Callable[[F], F]:
    """Use as a decorator to time the execution of any function.

    Args:
        prefix: String to print before the time taken.
            Default is the name of the function.
        precision: How many decimals to include in the seconds value.

    Examples:
        >>> @timer()
        ... def foo(x):
        ...     return x
        >>> foo(123)
        foo: 0.000...s
        123
        >>> @timer("Time taken: ", 2)
        ... def foo(x):
        ...     return x
        >>> foo(123)
        Time taken: 0.00s
        123

    """
    def decorator(func: F) -> F:
        @wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            nonlocal prefix
            prefix = prefix if prefix is not None else f"{func.__name__}: "
            start = perf_counter()
            result = func(*args, **kwargs)
            end = perf_counter()
            print(f"{prefix}{end - start:.{precision}f}s")
            return result
        return cast(F, wrapper)
    return decorator

Exemple d'utilisation:

from timer import timer


@timer(precision=9)
def takes_long(x: int) -> bool:
    return x in (i for i in range(x + 1))


print(takes_long(10**8))

Production:

takes_long: 4.942629056s
True

Les doctests peuvent être vérifiés avec:

$ python3 -m doctest --verbose -o=ELLIPSIS timer.py

Et le type indique:

$ mypy timer.py

1
C'est super cool, merci du partage. Je n'ai pas rencontré la bibliothèque de frappe ou le mot-clé non local - amusant de trouver de nouvelles choses à apprendre. Je vais avoir du mal à envelopper ma tête autour de ceci: Callable[[AnyF], AnyF]. Qu'est-ce que ça veut dire?
Danny

1
@Danny En haut, j'ai défini l'alias de type AnyFà signifier Callable[..., Any], ainsi AnyFest une fonction qui peut prendre n'importe quelle quantité d'arguments de type et retourner n'importe quoi. Il en Callable[[AnyF], AnyF]serait de même pour Callable[[Callable[..., Any]], Callable[..., Any]]. C'est le type de la valeur de retour de timeraka le type complet de decorator. C'est une fonction qui prend tout type de fonction comme seul argument et renvoie tout type de fonction.
ruohola

1
Merci pour l'explication! J'essaie toujours d'enrouler complètement ma tête autour de l'intérieur des décorateurs. Cela a beaucoup aidé!
Danny
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.