web-dev-qa-db-fra.com

Mesurer le temps écoulé en Python?

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 la documentation est source de confusion pour moi.

import timeit

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

Si vous souhaitez simplement mesurer le temps écoulé 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 la version 3.3 pourrait être d’utiliser perf_counter ou process_time , selon vos besoins. Avant la version 3.3, il était recommandé d’utiliser time.clock (merci orange ). Cependant, il est actuellement obsolète:

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

Sous Windows, cette fonction retourne les secondes de l'horloge murale écoulées depuis le premier appel à cette fonction, sous forme de nombre à virgule flottante, basé sur le Fonction Win32 QueryPerformanceCounter(). La résolution est typiquement mieux qu'une microseconde.

Déconseillé depuis la version 3.3: Le comportement de cette fonction dépend sur la plate-forme: use perf_counter() ou process_time() à la place de, en fonction de vos exigences, avoir un comportement bien défini.

1012
NPE

Utilisez timeit.default_timer au lieu de timeit.timeit. Le premier fournit automatiquement la meilleure horloge disponible sur votre plate-forme et votre 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 () vs time.time () - exactitude?

Voir également:

420
jfs

Python 3 uniquement:

Puisque time.clock () est obsolète à partir de Python 3.3 , vous voudrez utiliser time.perf_counter() pour le minutage global du système ou time.process_time() pour le minutage global du processus, comme vous l'avez utilisé utiliser time.clock():

import time

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

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

99
Pierre Prinetti

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

test.py:

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

la manière la plus simple d'utiliser timeit est 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.time ou time.clock (naïvement) pour comparer la vitesse des fonctions. Ils peuvent donner des résultats trompeurs .

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

73
unutbu

Je préfère ça. timeit doc 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 formatage ici, je viens d'écrire hh:mm:ss dans l'impression pour pouvoir interpréter time_elapsed

45
user1761806

C'est amusant de faire cela avec un gestionnaire de contexte qui mémorise automatiquement l'heure de début lors de l'entrée dans un bloc with, puis gèle l'heure de fin à la sortie du bloc. Avec un peu de 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'a pas cela (mais devrait probablement le faire). 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 contextmanager code 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 quelques codes de démonstration exécutables:

import time

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

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

43
gojomo

L'utilisation de time.time pour mesurer l'exécution vous donne le temps global d'exécution 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:

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

24
rocksportrocker

Voici une minuscule classe timer qui retourne 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
18
Danijel

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 de timeFunctions.py et à collecter les statistiques dans le fichier timeStats.profile. Notez que nous n'avons pas eu besoin d'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 de statistiques, vous pouvez exécuter le module pstats comme suit:

python -m pstats timeStats.profile

Cela lance le navigateur de statistiques interactif qui vous donne beaucoup de fonctionnalités de Nice. Pour votre cas d'utilisation particulier, vous pouvez simplement vérifier les statistiques de votre fonction. Dans notre exemple, vérifier les statistiques des 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 à éditer aucun de mes codes existants pour obtenir ces numéros et, évidemment, à aider au profilage.

16
sanchitarora

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

16
Brian Burns

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

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

il sort 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.

14
Leonid Ganeline

(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
12
Eyal Ch

Nous sommes en 2019 maintenant. Faisons-le de manière concise:

from ttictoc import TicToc
t = TicToc() ## TicToc("name")
t.tic();
# your code ...
t.toc();
print(t.elapsed)

Avantages de l’utilisation de cette approche au lieu d’autres:

  1. Concis et simple. il n'est pas nécessaire que le programmeur écrive des variables supplémentaires telles que:
    t1 = heure ()
    t2 = time ()
    écoulé = t2 - t1
  2. Avec nidification
t = TicToc(nested=True)
t.tic()
some code1...
t.tic()
some code2...
t.tic()
some code3...
print(t.toc()) # Prints time for code 3 
print(t.toc()) # Prints time for code 2 with code 3
print(t.toc()) # Prints time for code 1 with code 2 and 3
  1. Conservez les noms de votre tictoc.
t = TicToc("save user")
print(t.name)

Veuillez vous référer à ceci lien pour des instructions plus détaillées.

9
mervyn

sur python3:

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

élégant et court.

9
DmitrySemenov

Une sorte de super réponse plus tard, mais peut-être que ça sert à quelque chose. C’est une façon de le faire qui, à mon avis, est très 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 n'importe quelle autre fonction. À votre santé!

9
Andreas Herman

Je l'aime bien simple (python 3):

from timeit import timeit

timeit(lambda: print("hello"))

La sortie est microsecondes pour une exécution unique:

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 1 exécution unique est identique, mais en microsecondes en moyenne.


Pour les opérations lentes, ajoutez un nombre inférieur d'itérations, sinon vous pourriez attendre en permanence:

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
7
David

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
Kamlesh Verma

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

Tout d’abord, vous voulez toujours utiliser timeit et non time.time (et dans de nombreux cas, des API de compteur), car 

  1. timeit sélectionne la meilleure minuterie disponible sur votre système d'exploitation et la version Python. 
  2. timeit désactive la récupération de place, mais ce n'est pas quelque chose que vous ne voulez peut-être pas.

Le problème, c’est que timeit n’est pas aussi simple à utiliser car il a besoin d’être configuré et les choses deviennent laides lorsque vous importez beaucoup. Idéalement, vous voulez juste un décorateur ou utilisez le bloc with et mesurez le temps. Malheureusement, il n'y a rien d'intégré disponible pour cela, alors j'ai créé ci-dessous un petit module utilitaire.

Module utilitaire de synchronisation

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

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

class MeasureBlockTime:
    def __init__(self,name="(block)", no_print = False, disable_gc = True):
        self.name = name
        self.no_print = no_print
        self.disable_gc = disable_gc
    def __enter__(self):
        if self.disable_gc:
            self.gcold = gc.isenabled()
            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

Comment utiliser les fonctions de temps

Maintenant, vous pouvez chronométrer n'importe quelle fonction simplement en plaçant un décorateur devant elle:

import utils

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

Comment chronométrer les blocs

Si vous voulez chronométrer une partie du code, placez-le simplement dans le bloc with:

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 timer de timeit au lieu de time.time pour les raisons déjà décrites.
  2. Désactiver GC pendant le chronométrage.
  3. Decorator accepte les fonctions avec des paramètres nommés ou non nommés.
  4. Possibilité de désactiver l'impression en mode bloc (utilisez with utils.MeasureBlockTime() as t, puis t.elapsed).
  5. Possibilité de garder gc activé pour la synchronisation des blocs.
6
Shital Shah

Une autre façon d'utiliser timeit :

from timeit import timeit

def func():
    return 1 + 1

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

J'ai fait une bibliothèque pour cela, si vous voulez mesurer une fonction, vous pouvez simplement 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

5
karlpy

Pour avoir un aperçu de chaque appel de fonction de manière récursive, procédez comme suit:

%load_ext snakeviz
%%snakeviz

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

enter image description here

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 de faire fonctionner snakeviz en dehors des cahiers. Plus d'infos sur le site web de snakeviz .

5

Vous pouvez utiliser timeit.

Voici un exemple sur la façon de tester naive_func avec un paramètre utilisant 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 aucun paramètre. 

4
Vlad Bezden

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))
1
Gal Bracha

Le seul moyen auquel je peux penser est d'utiliser time.time().

import time
start = time.time()
sleep(5) #just to give it some delay to show it working
finish = time.time()
elapsed = finish - start
print(elapsed)

J'espère que ça va aider.

0
Trooper Z