Je comprends le concept de ce qui timeit
fait mais je ne sais pas comment l'implémenter dans mon code.
Comment comparer deux fonctions, disons insertion_sort
et tim_sort
, avec timeit
?
La façon dont timeit fonctionne consiste à exécuter une fois le code d'installation, puis à effectuer des appels répétés à une série d'instructions. Donc, si vous voulez tester le tri, une certaine prudence est requise afin qu'un passage à un tri sur place n'affecte pas le prochain passage avec des données déjà triées (ce qui, bien sûr, ferait vraiment briller le Timsort car il fonctionne mieux lorsque les données sont déjà partiellement commandées).
Voici un exemple de configuration d'un test de tri:
>>> import timeit
>>> setup = '''
import random
random.seed('slartibartfast')
s = [random.random() for i in range(1000)]
timsort = list.sort
'''
>>> print min(timeit.Timer('a=s[:]; timsort(a)', setup=setup).repeat(7, 1000))
0.334147930145
Notez que la série d'instructions crée une nouvelle copie des données non triées à chaque passage.
Notez également la technique de synchronisation consistant à exécuter la suite de mesures sept fois et à ne conserver que le meilleur moment - cela peut vraiment aider à réduire les distorsions de mesure dues à d'autres processus en cours d'exécution sur votre système.
Ce sont mes conseils pour utiliser correctement timeit. J'espère que cela t'aides :-)
timsort(a)
et prenez la différence :-).repeat(7,1000)
déjà (en utilisant la même graine)! Votre solution est donc parfaite IMO..repeat(7, 1000)
vs.repeat(2, 3500)
vs.repeat(35, 200
) devrait dépendre de la façon dont l'erreur due à la charge du système se compare à l'erreur due à la variabilité des entrées. Dans le cas extrême, si votre système est toujours sous forte charge et que vous voyez une longue queue mince à gauche de la distribution du temps d'exécution (lorsque vous l'attrapez dans un état inactif rare), vous pourriez même trouver.repeat(7000,1)
plus utile que.repeat(7,1000)
si vous ne peut pas budgéter plus de 7 000 exécutions.Si vous souhaitez utiliser
timeit
dans une session Python interactive, il existe deux options pratiques:Utilisez le shell IPython . Il dispose de la
%timeit
fonction spéciale pratique :Dans un interpréteur Python standard, vous pouvez accéder aux fonctions et autres noms que vous avez définis plus tôt au cours de la session interactive en les important
__main__
dans l'instruction setup:la source
from __main__ import f
technique. Je ne pense pas que ce soit aussi largement connu qu'il devrait l'être. Il est utile dans des cas comme celui-ci où un appel de fonction ou de méthode est synchronisé. Dans d'autres cas (chronométrage d'une série d'étapes), cela est moins utile car il introduit une surcharge d'appel de fonction.%timeit f(x)
sys._getframe(N).f_globals
) aient été par défaut depuis le début.Je vais vous révéler un secret: la meilleure façon de l'utiliser
timeit
est en ligne de commande.Sur la ligne de commande,
timeit
fait une analyse statistique appropriée: il vous indique combien de temps a duré le plus court. C'est bien parce que toute erreur de synchronisation est positive. Ainsi, le temps le plus court contient le moins d'erreurs. Il n'y a aucun moyen d'obtenir une erreur négative car un ordinateur ne peut jamais calculer plus vite qu'il ne peut le faire!Ainsi, l'interface de ligne de commande:
C'est assez simple, hein?
Vous pouvez configurer des choses:
ce qui est utile aussi!
Si vous voulez plusieurs lignes, vous pouvez utiliser la continuation automatique du shell ou utiliser des arguments séparés:
Cela donne une configuration de
et fois
Si vous souhaitez avoir des scripts plus longs, vous pourriez être tenté de passer à l'
timeit
intérieur d'un script Python. Je suggère d'éviter cela parce que l'analyse et le timing sont tout simplement meilleurs sur la ligne de commande. Au lieu de cela, j'ai tendance à faire des scripts shell:Cela peut prendre un peu plus de temps en raison des multiples initialisations, mais normalement ce n'est pas un gros problème.
Mais que faire si vous souhaitez utiliser l'
timeit
intérieur de votre module?Eh bien, le moyen le plus simple est de faire:
et cela vous donne un temps cumulé ( pas minimum!) pour exécuter ce nombre de fois.
Pour obtenir une bonne analyse, utilisez
.repeat
et prenez le minimum:Vous devez normalement combiner cela avec
functools.partial
au lieu delambda: ...
pour réduire les frais généraux. Ainsi, vous pourriez avoir quelque chose comme:Vous pouvez également faire:
ce qui vous donnerait quelque chose de plus proche de l' interface depuis la ligne de commande, mais d'une manière beaucoup moins cool. Le
"from __main__ import ..."
vous permet d'utiliser le code de votre module principal à l'intérieur de l'environnement artificiel créé partimeit
.Il convient de noter qu'il s'agit d'un emballage pratique
Timer(...).timeit(...)
et qu'il n'est donc pas particulièrement bon pour le timing. Personnellement, je préfère de loin utiliserTimer(...).repeat(...)
comme je l'ai montré ci-dessus.Avertissements
Il y a quelques mises en garde
timeit
qui tiennent partout.Les frais généraux ne sont pas pris en compte. Dites que vous voulez chronométrer
x += 1
, pour savoir combien de temps prend l'addition:Eh bien, ce n'est pas 0,0476 µs. Vous savez seulement que c'est moins que ça. Toute erreur est positive.
Essayez donc de trouver des frais généraux purs :
C'est un bon 30% de frais généraux rien que du timing! Cela peut fausser considérablement les synchronisations relatives. Mais vous ne vous souciez que de l' ajout de timings; les horaires de recherche
x
doivent également être inclus dans les frais généraux:La différence n'est pas beaucoup plus grande, mais elle est là.
Les méthodes de mutation sont dangereuses.
Mais c'est complètement faux!
x
est la liste vide après la première itération. Vous devrez réinitialiser:Mais alors vous avez beaucoup de frais généraux. Tenez-en compte séparément.
Notez que la soustraction de la surcharge n'est raisonnable ici que parce que la surcharge est une petite fraction du temps.
Pour votre exemple, il convient de noter que le tri par insertion et le tri temporel ont tous deux des comportements temporels inhabituels pour les listes déjà triées. Cela signifie que vous aurez besoin d'un
random.shuffle
tri entre si vous voulez éviter de perturber vos horaires.la source
timeit
partir d'un programme mais fonctionnant de la même manière que la ligne de commande? .timeit
exécute unepass
instruction lorsque aucun argument n'est donné, ce qui, bien sûr, prend un certain temps. Si des arguments sont fournis,pass
ils ne seront pas exécutés, donc soustraire certains0.014
usecs de chaque synchronisation serait incorrect.Si vous souhaitez comparer rapidement deux blocs de code / fonctions, vous pouvez le faire:
la source
Je trouve que le moyen le plus simple d'utiliser timeit est à partir de la ligne de commande:
Étant donné test.py :
exécutez timeit comme ceci:
la source
pour moi, c'est le moyen le plus rapide:
la source
la source
Cela fonctionne très bien:
la source
permet de configurer le même dictionnaire dans chacun des éléments suivants et de tester le temps d'exécution.
L'argument de configuration consiste essentiellement à configurer le dictionnaire
Le numéro est d'exécuter le code 1000000 fois. Pas la configuration mais le stmt
Lorsque vous exécutez cela, vous pouvez voir que l'index est bien plus rapide que get. Vous pouvez l'exécuter plusieurs fois pour voir.
Le code essaie essentiellement d'obtenir la valeur de c dans le dictionnaire.
Voici mes résultats, les vôtres seront différents.
par indice: 0.20900007452246427
par get: 0.54841166886888
la source
passez simplement votre code entier comme argument de timeit:
la source
la source
gc.enable()
?Le module timeit intégré fonctionne mieux à partir de la ligne de commande IPython.
Pour chronométrer des fonctions à partir d'un module:
la source
Exemple d'utilisation de l'interpréteur Python REPL avec une fonction qui accepte des paramètres.
la source
Vous devez créer deux fonctions, puis exécuter quelque chose de similaire à ceci. Remarquez que vous souhaitez choisir le même nombre d'exécutions / exécutions pour comparer pomme à pomme.
Cela a été testé sous Python 3.7.
Voici le code pour le copier facilement
la source