web-dev-qa-db-fra.com

Python fonction de mesure du temps

Je veux créer une fonction python pour tester le temps passé dans chaque fonction et afficher son nom avec son heure. Comment puis-je imprimer le nom de la fonction et s'il existe un autre moyen de le faire?

def measureTime(a):
    start = time.clock() 
    a()
    elapsed = time.clock()
    elapsed = elapsed - start
    print "Time spent in (function name) is: ", elapsed
114
Wazery

D'abord et avant tout, je suggère fortement d'utiliser un profileur ou au moins une utilisation timeit .

Cependant, si vous voulez écrire votre propre méthode de chronométrage pour apprendre, voici un endroit pour commencer à utiliser un décorateur.

Python 2:

def timing(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print '%s function took %0.3f ms' % (f.func_name, (time2-time1)*1000.0)
        return ret
    return wrap

Et l'utilisation est très simple, utilisez simplement le décorateur @timing:

@timing
def do_work():
  #code

Python 3:

def timing(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))

        return ret
    return wrap

Remarque J'appelle f.func_name pour obtenir le nom de la fonction sous forme de chaîne (dans Python 2) ou f.__name__ dans Python 3.

228
Mike Lewis

Après avoir joué avec le module timeit, je n’aime pas son interface, qui n’est pas aussi élégante que les deux méthodes suivantes.

Le code suivant est dans Python 3.

La méthode du décorateur

C'est presque la même chose avec la méthode de @ Mike. Ici, j'ajoute kwargs et functools wrap pour le rendre meilleur.

def timeit(func):
    @functools.wraps(func)
    def newfunc(*args, **kwargs):
        startTime = time.time()
        func(*args, **kwargs)
        elapsedTime = time.time() - startTime
        print('function [{}] finished in {} ms'.format(
            func.__name__, int(elapsedTime * 1000)))
    return newfunc

@timeit
def foobar():
    mike = Person()
    mike.think(30)

La méthode du gestionnaire de contexte

from contextlib import contextmanager

@contextmanager
def timeit_context(name):
    startTime = time.time()
    yield
    elapsedTime = time.time() - startTime
    print('[{}] finished in {} ms'.format(name, int(elapsedTime * 1000)))

Par exemple, vous pouvez l'utiliser comme:

with timeit_context('My profiling code'):
    mike = Person()
    mike.think()

Et le code dans le bloc with sera chronométré.

Conclusion

En utilisant la première méthode, vous pouvez commenter facilement le décorateur pour obtenir le code normal. Cependant, il ne peut chronométrer qu'une fonction. Si vous avez une partie du code que vous ne voulez pas quoi en faire une fonction, alors vous pouvez choisir la deuxième méthode.

Par exemple, maintenant vous avez

images = get_images()
bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Maintenant, vous voulez chronométrer la ligne bigImage = .... Si vous le changez en fonction, ce sera:

images = get_images()
bitImage = None
@timeit
def foobar():
    nonlocal bigImage
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)

Ça n'a pas l'air génial ... Et si vous êtes dans Python 2, qui n'a pas de mot clé nonlocal.

Au lieu de cela, l’utilisation de la deuxième méthode est très bien adaptée ici:

images = get_images()
with timeit_context('foobar'):
    bigImage = ImagePacker.pack(images, width=4096)
drawer.draw(bigImage)
44
Ray

Je ne vois pas quel est le problème avec le module timeit. C'est probablement la manière la plus simple de le faire.

import timeit
timeit.timeit(a, number=1)

Il est également possible d'envoyer des arguments aux fonctions. Tout ce dont vous avez besoin est d’envelopper votre fonction en utilisant des décorateurs. Plus d'explications ici: http://www.pythoncentral.io/time-a-python-function/

Le seul cas où vous voudriez peut-être écrire vos propres déclarations de minutage est si vous voulez exécuter une fonction une seule fois et souhaitez également obtenir sa valeur de retour.

L'avantage d'utiliser le module timeit est qu'il vous permet de répéter le nombre d'exécutions. Cela peut être nécessaire car d’autres processus risquent d’interférer avec la précision de votre minutage. Donc, vous devriez l'exécuter plusieurs fois et regarder la valeur la plus basse.

11
Phani

Timeit a deux gros défauts: il ne renvoie pas la valeur de retour de la fonction et utilise eval, ce qui nécessite de transmettre un code de configuration supplémentaire pour les importations. Cela résout les problèmes de manière simple et élégante:

def timed(f):
  start = time.time()
  ret = f()
  elapsed = time.time() - start
  return ret, elapsed

timed(lambda: database.foo.execute('select count(*) from source.apachelog'))
(<sqlalchemy.engine.result.ResultProxy object at 0x7fd6c20fc690>, 4.07547402381897)
9
Jonathan Ray

Méthode Decorator utilisant la bibliothèque decorator Python:

import decorator

@decorator
def timing(func, *args, **kwargs):
    '''Function timing wrapper
        Example of using:
        ``@timing()``
    '''

    fn = '%s.%s' % (func.__module__, func.__name__)

    timer = Timer()
    with timer:
        ret = func(*args, **kwargs)

    log.info(u'%s - %0.3f sec' % (fn, timer.duration_in_seconds()))
    return ret

Voir l'article sur mon blog:

publier sur le blog mobilepro.pl

mon post sur Google Plus

3
MobilePro.pl

Il existe un outil simple pour le timing. https://github.com/RalphMao/PyTimer

Cela peut fonctionner comme un décorateur :

from pytimer import Timer
@Timer(average=False)      
def matmul(a,b, times=100):
    for i in range(times):
        np.dot(a,b)        

Sortie:

matmul:0.368434
matmul:2.839355

Il peut également fonctionner comme un minuteur de plug-in avec un contrôle d'espace de nom (utile si vous l'insérez dans une fonction comportant beaucoup de codes et pouvant être appelé n'importe où ailleurs).

timer = Timer()                                           
def any_function():                                       
    timer.start()                                         

    for i in range(10):                                   

        timer.reset()                                     
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block1')                        

        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
        timer.checkpoint('block2')                        
        np.dot(np.ones((100,1000)), np.zeros((1000,1000)))

    for j in range(20):                                   
        np.dot(np.ones((100,1000)), np.zeros((1000,500)))
    timer.summary()                                       

for i in range(2):                                        
    any_function()                                        

Sortie:

========Timing Summary of Default Timer========
block2:0.065062
block1:0.032529
========Timing Summary of Default Timer========
block2:0.065838
block1:0.032891

J'espère que ça va aider

3
ralphmao95

Ma façon de le faire:

from time import time

def printTime(start):
    end = time()
    duration = end - start
    if duration < 60:
        return "used: " + str(round(duration, 2)) + "s."
    else:
        mins = int(duration / 60)
        secs = round(duration % 60, 2)
        if mins < 60:
            return "used: " + str(mins) + "m " + str(secs) + "s."
        else:
            hours = int(duration / 3600)
            mins = mins % 60
            return "used: " + str(hours) + "h " + str(mins) + "m " + str(secs) + "s."

Définissez une variable comme start = time() avant d'exécuter la/les boucle (s), et printTime(start) juste après le bloc.

et vous avez la réponse.

2
Adam Liu