web-dev-qa-db-fra.com

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

J'ai un script python qui fonctionne comme il se doit, mais j'ai besoin d'écrire le temps d'exécution. J'ai cherché sur Google que je devrais 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 qu'il faut pour exécuter la requête et l'écrire dans le fichier results_update.txt. Le but est de tester une instruction de mise à jour pour ma base de données avec différents index et mécanismes de réglage.

132
Mestika

Vous pouvez utiliser time.time() ou 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 précise que timeit (elle ne fait pas la moyenne de plusieurs exécutions) mais elle est simple.

time.time() (sous Windows et Linux) et time.clock() (sous Linux) ne sont pas assez précis pour des fonctions rapides (vous obtenez total = 0). Dans ce cas ou si vous voulez moyenner le temps écoulé par plusieurs exécutions, vous devez appeler manuellement la fonction plusieurs fois (comme je le pense déjà dans votre exemple de code et time, il le fait automatiquement lorsque vous définissez son numéro 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érable à time.time().

228
joaquin

Si vous profilez votre code et pouvez utiliser IPython, il a la fonction magique %timeit.

%%timeit fonctionne 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
39
munk

Indépendamment du 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), puis lorsque vous effectuez le premier appel à exécuter, vous lui transmettez une variable locale query_stmt que vous initialisez seulement après l'appel à exécuter.

Tout d’abord, corrigez votre code sans vous soucier du temps: c’est-à-dire une fonction qui établit ou reçoit une connexion et effectue 100, 500 ou quel que soit le 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 timeit dessus!

Plus précisément, si la fonction que vous voulez chronométrer est une fonction sans paramètre appelée foobar, vous pouvez utiliser timeit.timeit (2.6 ou version ultérieure, ce qui est plus compliqué dans les versions 2.5 et antérieures):

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

Vous feriez mieux de spécifier le nombre de pistes car la valeur par défaut, un million, peut être élevée pour votre cas d'utilisation (ce qui vous obligerait à passer beaucoup de temps dans ce code ;-).

33
Alex Martelli

Concentrez-vous sur une chose spécifique . Les E/S de disque sont lentes, donc je retirerais cela du test si tout ce que vous allez faire sur Tweak est la requête de la base de données.

Et si vous devez planifier l'exécution de votre base de données, recherchez plutôt des outils de base de données, comme demander le plan de requête, et notez que les performances varient non seulement avec la requête exacte et vos index, mais également en fonction du chargement de données (quantité de données). vous avez stocké).

Cela dit, vous pouvez simplement mettre votre code dans une fonction et l'exécuter avec timeit.timeit() :

def function_to_repeat():
    # ...

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

Ceci désactiverait la collecte des ordures, appellerait à plusieurs reprises la fonction function_to_repeat(), et chronométrer la durée totale de ces appels en utilisant timeit.default_timer() , qui est l'horloge la plus précise disponible. pour votre plate-forme spécifique.

Vous devez déplacer le code de configuration vers l'extérieur de la fonction répétée; Par exemple, vous devez d'abord vous connecter à la base de données, puis ne chronométrer que les requêtes. Utilisez l'argument setup pour importer ou créer ces dépendances et transmettez-les à 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)

prendrait les globales function_to_repeat, var1 et var2 de votre script et les transmettrait à la fonction à chaque répétition.

8
Martijn Pieters

Voici un simple emballage pour la réponse de Steven. Cette fonction ne fait pas de répétitions/moyennes répétées, vous évite simplement de devoir 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))

Je vois que la question a déjà été répondu, mais je veux toujours ajouter mes 2 cents pour les mêmes.

J'ai également fait face à un scénario similaire dans lequel je dois tester les temps d'exécution pour plusieurs approches et donc écrit un petit script, qui appelle timeit sur toutes les fonctions écrites dans celui-ci.

Le script est également disponible en tant que github Gist ici .

J'espère que cela vous aidera et aidera les autres.

from random import random
import types

def list_without_comprehension():
    l = []
    for i in xrange(1000):
        l.append(int(random()*100 % 100))
    return l

def list_with_comprehension():
    # 1K random numbers between 0 to 100
    l = [int(random()*100 % 100) for _ in xrange(1000)]
    return l


# operations on list_without_comprehension
def sort_list_without_comprehension():
    list_without_comprehension().sort()

def reverse_sort_list_without_comprehension():
    list_without_comprehension().sort(reverse=True)

def sorted_list_without_comprehension():
    sorted(list_without_comprehension())


# operations on list_with_comprehension
def sort_list_with_comprehension():
    list_with_comprehension().sort()

def reverse_sort_list_with_comprehension():
    list_with_comprehension().sort(reverse=True)

def sorted_list_with_comprehension():
    sorted(list_with_comprehension())


def main():
    objs = globals()
    funcs = []
    f = open("timeit_demo.sh", "w+")

    for objname in objs:
        if objname != 'main' and type(objs[objname]) == types.FunctionType:
            funcs.append(objname)
    funcs.sort()
    for func in funcs:
        f.write('''echo "Timing: %(funcname)s"
python -m timeit "import timeit_demo; timeit_demo.%(funcname)s();"\n\n
echo "------------------------------------------------------------"
''' % dict(
                funcname = func,
                )
            )

    f.close()

if __== "__main__":
    main()

    from os import system

    #Works only for *nix platforms
    system("/bin/bash timeit_demo.sh")

    #un-comment below for windows
    #system("cmd timeit_demo.sh")
2
Abhijit Mamarde