236 votes

Comment puis-je chronométrer un segment de code pour tester les performances avec Pythons timeit ?

J'ai un script en python qui fonctionne comme il se doit, mais j'ai besoin d'écrire le temps d'exécution. J'ai trouvé sur Google que je devais utiliser timeit mais je n'arrive pas à le faire fonctionner.

Mon script Python ressemble à ceci :

import sys
import getopt
import timeit
import random
import os
import re
import ibm_db
import time
from string import maketrans
myfile = open("results_update.txt", "a")

for r in range(100):
    rannumber = random.randint(0, 100)

    update = "update TABLE set val = %i where MyCount >= '2010' and MyCount < '2012' and number = '250'" % rannumber
    #print rannumber

    conn = ibm_db.pconnect("dsn=myDB","usrname","secretPWD")

for r in range(5):
    print "Run %s\n" % r        
    ibm_db.execute(query_stmt)
 query_stmt = ibm_db.prepare(conn, update)

myfile.close()
ibm_db.close(conn)

Ce dont j'ai besoin, c'est du temps nécessaire pour exécuter la requête et l'écrire dans le fichier. results_update.txt . L'objectif est de tester une instruction de mise à jour pour ma base de données avec différents index et mécanismes de réglage.

382voto

joaquin Points 22450

Vous pouvez utiliser time.time() o time.clock() avant et après le bloc que vous souhaitez chronométrer.

import time

t0 = time.time()
code_block
t1 = time.time()

total = t1-t0

Cette méthode n'est pas aussi exacte que timeit (il ne s'agit pas d'une moyenne de plusieurs exécutions), mais il est simple.

time.time() (sous Windows et Linux) et time.clock() (dans Linux) ne sont pas assez précises pour les fonctions rapides (on obtient total = 0). Dans ce cas, ou si vous voulez faire la moyenne du temps écoulé par plusieurs exécutions, vous devez appeler manuellement la fonction plusieurs fois (comme je pense que vous le faites déjà dans votre code d'exemple et que timeit le fait automatiquement lorsque vous définissez sa fonction nombre argument)

import time

def myfast():
   code

n = 10000
t0 = time.time()
for i in range(n): myfast()
t1 = time.time()

total_n = t1-t0

Dans Windows, comme Corey l'a indiqué dans le commentaire, time.clock() a une précision beaucoup plus élevée (microseconde au lieu de seconde) et est préféré à time.time() .

63voto

munkhd Points 1876

Si vous profilez votre code et que vous pouvez utiliser IPython, celui-ci dispose de la fonction magique %timeit .

%%timeit opère sur les cellules.

In [2]: %timeit cos(3.14)
10000000 loops, best of 3: 160 ns per loop

In [3]: %%timeit
   ...: cos(3.14)
   ...: x = 2 + 3
   ...: 
10000000 loops, best of 3: 196 ns per loop

43voto

Alex Martelli Points 330805

Outre le timing, le code que vous montrez est tout simplement incorrect : vous exécutez 100 connexions (en ignorant complètement toutes les connexions sauf la dernière), et lorsque vous faites le premier appel à execute, vous lui passez une variable locale query_stmt que vous initialisez seulement après l'appel d'exécution.

Tout d'abord, faites en sorte que votre code soit correct, sans vous préoccuper pour l'instant du timing : c'est-à-dire une fonction qui établit ou reçoit une connexion et effectue 100 ou 500 ou n'importe quel nombre de mises à jour sur cette connexion, puis ferme la connexion. Une fois que votre code fonctionne correctement, c'est le bon moment pour penser à utiliser la fonction timeit sur elle !

Plus précisément, si la fonction que vous souhaitez chronométrer est une fonction sans paramètre appelée foobar vous pouvez utiliser timeit.timeit (2.6 ou plus récent -- c'est plus compliqué en 2.5 et avant) :

timeit.timeit('foobar()', number=1000)

Depuis la version 3.5, les globals permet d'utiliser directement le paramètre timeit avec des fonctions qui prennent des paramètres :

timeit.timeit('foobar(x,y)', number=1000, globals = globals())

Il est préférable de spécifier le nombre d'exécutions car la valeur par défaut, un million, peut être trop élevée pour votre cas d'utilisation (ce qui vous amènera à passer beaucoup de temps dans ce code;-).

15voto

Martijn Pieters Points 271458

Focus sur une chose précise . Les entrées/sorties sur disque sont lentes, donc j'enlèverais ce point du test si tout ce que vous voulez modifier est la requête de la base de données.

Si vous avez besoin de chronométrer l'exécution de votre base de données, utilisez plutôt des outils de base de données, comme demander le plan de requête, et notez que les performances varient non seulement en fonction de la requête exacte et des index dont vous disposez, mais aussi en fonction de la charge de données (la quantité de données stockées).

Cela dit, vous pouvez simplement placer votre code dans une fonction et exécuter cette fonction avec la commande timeit.timeit() :

def function_to_repeat():
    # ...

duration = timeit.timeit(function_to_repeat, number=1000)

Cela désactiverait le ramassage des ordures, appellerait de façon répétée la fonction function_to_repeat() et chronométrer la durée totale de ces appels à l'aide de la fonction timeit.default_timer() qui est l'horloge la plus précise disponible pour votre plate-forme spécifique.

Vous devriez déplacer le code de configuration sortir de la fonction répétée ; par exemple, vous devriez d'abord vous connecter à la base de données, puis ne chronométrer que les requêtes. Utilisez la fonction setup pour importer ou créer ces dépendances et les transmettre à votre fonction :

def function_to_repeat(var1, var2):
    # ...

duration = timeit.timeit(
    'function_to_repeat(var1, var2)',
    'from __main__ import function_to_repeat, var1, var2', 
    number=1000)

récupèrerait les globaux function_to_repeat , var1 y var2 de votre script et transmettez-les à la fonction à chaque répétition.

7voto

Voici un simple wrapper pour la réponse de Steven. Cette fonction ne fait pas d'exécutions répétées ni de moyenne, elle vous évite simplement d'avoir à répéter le code de chronométrage partout :)

'''function which prints the wall time it takes to execute the given command'''
def time_func(func, *args): #*args can take 0 or more 
  import time
  start_time = time.time()
  func(*args)
  end_time = time.time()
  print("it took this long to run: {}".format(end_time-start_time))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X