Quel est l'équivalent Python des fonctions tic et toc de Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
alors print toc-tic
.
Quel est l'équivalent Python des fonctions tic et toc de Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
alors print toc-tic
.
Réponses:
Mis à part timeit
ce que ThiefMaster a mentionné, un moyen simple de le faire est juste (après l'importation time
):
t = time.time()
# do stuff
elapsed = time.time() - t
J'ai une classe d'aide que j'aime utiliser:
class Timer(object):
def __init__(self, name=None):
self.name = name
def __enter__(self):
self.tstart = time.time()
def __exit__(self, type, value, traceback):
if self.name:
print('[%s]' % self.name,)
print('Elapsed: %s' % (time.time() - self.tstart))
Il peut être utilisé comme gestionnaire de contexte:
with Timer('foo_stuff'):
# do some foo
# do some stuff
Parfois, je trouve cette technique plus pratique que timeit
- tout dépend de ce que vous voulez mesurer.
time
commande unix pour mesurer les temps d'exécution des programmes, et cette méthode reproduit cela dans le code Python. Je ne vois rien de mal à cela, tant que c'est le bon outil pour le travail. timeit
n'est pas toujours cela, et un profileur est une solution beaucoup plus lourde pour la plupart des besoins
print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'
. C'est difficile à comprendre sans le% .2f. Merci pour cette excellente idée.
elapsed = t - time.time()
, au lieu de elapsed = time.time() - t
. Dans ce dernier écoulé sera négatif. J'ai suggéré ce changement en tant que modification.
elapsed = time.time() - t
c'est la forme qui donne toujours une valeur positive.
J'ai eu la même question lorsque j'ai migré vers python depuis Matlab. Avec l'aide de ce fil, j'ai pu construire un analogue exact du Matlab tic()
et des toc()
fonctions. Insérez simplement le code suivant en haut de votre script.
import time
def TicTocGenerator():
# Generator that returns time differences
ti = 0 # initial time
tf = time.time() # final time
while True:
ti = tf
tf = time.time()
yield tf-ti # returns the time difference
TicToc = TicTocGenerator() # create an instance of the TicTocGen generator
# This will be the main function through which we define both tic() and toc()
def toc(tempBool=True):
# Prints the time difference yielded by generator instance TicToc
tempTimeInterval = next(TicToc)
if tempBool:
print( "Elapsed time: %f seconds.\n" %tempTimeInterval )
def tic():
# Records a time in TicToc, marks the beginning of a time interval
toc(False)
C'est tout! Nous sommes maintenant prêts à être pleinement utilisés tic()
et toc()
comme dans Matlab. Par exemple
tic()
time.sleep(5)
toc() # returns "Elapsed time: 5.00 seconds."
En fait, c'est plus polyvalent que les fonctions Matlab intégrées. Ici, vous pouvez créer une autre instance de TicTocGenerator
pour suivre plusieurs opérations ou simplement pour chronométrer les choses différemment. Par exemple, tout en chronométrant un script, nous pouvons désormais chronométrer chaque élément du script séparément, ainsi que le script entier. (Je vais donner un exemple concret)
TicToc2 = TicTocGenerator() # create another instance of the TicTocGen generator
def toc2(tempBool=True):
# Prints the time difference yielded by generator instance TicToc2
tempTimeInterval = next(TicToc2)
if tempBool:
print( "Elapsed time 2: %f seconds.\n" %tempTimeInterval )
def tic2():
# Records a time in TicToc2, marks the beginning of a time interval
toc2(False)
Vous devriez maintenant pouvoir chronométrer deux choses distinctes: Dans l'exemple suivant, nous chronométrons le script total et les parties d'un script séparément.
tic()
time.sleep(5)
tic2()
time.sleep(3)
toc2() # returns "Elapsed time 2: 5.00 seconds."
toc() # returns "Elapsed time: 8.00 seconds."
En fait, vous n'avez même pas besoin de l'utiliser à tic()
chaque fois. Si vous avez une série de commandes que vous souhaitez chronométrer, vous pouvez écrire
tic()
time.sleep(1)
toc() # returns "Elapsed time: 1.00 seconds."
time.sleep(2)
toc() # returns "Elapsed time: 2.00 seconds."
time.sleep(3)
toc() # returns "Elapsed time: 3.00 seconds."
# and so on...
J'espère que cela est utile.
Le meilleur analogue absolu de tic et toc serait de simplement les définir en python.
def tic():
#Homemade version of matlab tic and toc functions
import time
global startTime_for_tictoc
startTime_for_tictoc = time.time()
def toc():
import time
if 'startTime_for_tictoc' in globals():
print "Elapsed time is " + str(time.time() - startTime_for_tictoc) + " seconds."
else:
print "Toc: start time not set"
Ensuite, vous pouvez les utiliser comme:
tic()
# do stuff
toc()
tic
et toc
, que Matlab prend en charge. Un peu plus de sophistication serait nécessaire.
import time
extérieur des deux fonctions, car cela peut prendre un certain temps.
tic
pousser et toc
sortez d'elle.
timeit.default_timer()
c'est mieux que time.time()
parce que cela time.clock()
pourrait être plus approprié selon le système d'exploitation
Habituellement, IPython de %time
, %timeit
, %prun
et %lprun
(si l' on a line_profiler
installé) satisfaire mes besoins de profilage très bien. Cependant, un cas d'utilisation pour une tic-toc
fonctionnalité similaire est apparu lorsque j'ai essayé de profiler des calculs qui étaient pilotés de manière interactive, c'est-à-dire par le mouvement de la souris de l'utilisateur dans une interface graphique. J'avais l'impression que spammer les tic
s et toc
s dans les sources tout en testant de manière interactive serait le moyen le plus rapide de révéler les goulots d'étranglement. Je suis allé avec la Timer
classe d' Eli Bendersky , mais je n'étais pas entièrement satisfait, car cela m'obligeait à changer l'indentation de mon code, ce qui peut être gênant pour certains éditeurs et confond le système de contrôle de version. De plus, il peut être nécessaire de mesurer le temps entre les points dans différentes fonctions, ce qui ne fonctionnerait pas avec lewith
déclaration. Après avoir essayé beaucoup d'intelligence Python, voici la solution simple que j'ai trouvée fonctionnant le mieux:
from time import time
_tstart_stack = []
def tic():
_tstart_stack.append(time())
def toc(fmt="Elapsed: %s s"):
print fmt % (time() - _tstart_stack.pop())
Comme cela fonctionne en poussant les heures de départ sur une pile, cela fonctionnera correctement pour plusieurs niveaux de tic
s et de toc
s. Cela permet également de changer la chaîne de format de l' toc
instruction pour afficher des informations supplémentaires, ce que j'ai aimé sur la Timer
classe d'Eli .
Pour une raison quelconque, je me suis préoccupé de la surcharge d'une implémentation pure Python, alors j'ai également testé un module d'extension C:
#include <Python.h>
#include <mach/mach_time.h>
#define MAXDEPTH 100
uint64_t start[MAXDEPTH];
int lvl=0;
static PyObject* tic(PyObject *self, PyObject *args) {
start[lvl++] = mach_absolute_time();
Py_RETURN_NONE;
}
static PyObject* toc(PyObject *self, PyObject *args) {
return PyFloat_FromDouble(
(double)(mach_absolute_time() - start[--lvl]) / 1000000000L);
}
static PyObject* res(PyObject *self, PyObject *args) {
return tic(NULL, NULL), toc(NULL, NULL);
}
static PyMethodDef methods[] = {
{"tic", tic, METH_NOARGS, "Start timer"},
{"toc", toc, METH_NOARGS, "Stop timer"},
{"res", res, METH_NOARGS, "Test timer resolution"},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
inittictoc(void) {
Py_InitModule("tictoc", methods);
}
C'est pour MacOSX, et j'ai omis le code pour vérifier s'il lvl
est hors limites par souci de concision. Bien que tictoc.res()
donne une résolution d'environ 50 nanosecondes sur mon système, j'ai trouvé que l'instabilité de la mesure de toute instruction Python se situe facilement dans la plage de la microseconde (et bien plus encore lorsqu'elle est utilisée à partir d'IPython). À ce stade, la surcharge de l'implémentation Python devient négligeable, de sorte qu'elle peut être utilisée avec la même confiance que l'implémentation C.
J'ai trouvé que l'utilité de l' tic-toc
approche -approach est pratiquement limitée aux blocs de code qui prennent plus de 10 microsecondes à exécuter. En dessous, des stratégies de calcul de la moyenne comme dans timeit
sont nécessaires pour obtenir une mesure fidèle.
Vous pouvez utiliser tic
et à toc
partir de ttictoc
. Installez-le avec
pip install ttictoc
Et importez-les simplement dans votre script comme suit
from ttictoc import tic,toc
tic()
# Some code
print(toc())
Je viens de créer un module [tictoc.py] pour réaliser des tic tocs imbriqués, ce que fait Matlab.
from time import time
tics = []
def tic():
tics.append(time())
def toc():
if len(tics)==0:
return None
else:
return time()-tics.pop()
Et cela fonctionne de cette façon:
from tictoc import tic, toc
# This keeps track of the whole process
tic()
# Timing a small portion of code (maybe a loop)
tic()
# -- Nested code here --
# End
toc() # This returns the elapse time (in seconds) since the last invocation of tic()
toc() # This does the same for the first tic()
J'espère que cela aide.
Jetez un œil au timeit
module. Ce n'est pas vraiment équivalent mais si le code que vous voulez chronométrer est à l'intérieur d'une fonction, vous pouvez facilement l'utiliser.
timeit
c'est mieux pour les benchmarks. Il n'est même pas nécessaire que ce soit une fonction unique, vous pouvez passer des instructions abritement complexes.
pip install easy-tictoc
Dans le code:
from tictoc import tic, toc
tic()
#Some code
toc()
Avertissement: je suis l'auteur de cette bibliothèque.
Cela peut également être fait à l'aide d'un wrapper. Façon très générale de garder le temps.
L'encapsuleur de cet exemple de code encapsule n'importe quelle fonction et imprime le temps nécessaire pour exécuter la fonction:
def timethis(f):
import time
def wrapped(*args, **kwargs):
start = time.time()
r = f(*args, **kwargs)
print "Executing {0} took {1} seconds".format(f.func_name, time.time()-start)
return r
return wrapped
@timethis
def thistakestime():
for x in range(10000000):
pass
thistakestime()
J'ai changé un peu la réponse de @Eli Bendersky pour utiliser le ctor __init__()
et le dtor __del__()
pour faire le timing, afin qu'il puisse être utilisé plus facilement sans indenter le code d'origine:
class Timer(object):
def __init__(self, name=None):
self.name = name
self.tstart = time.time()
def __del__(self):
if self.name:
print '%s elapsed: %.2fs' % (self.name, time.time() - self.tstart)
else:
print 'Elapsed: %.2fs' % (time.time() - self.tstart)
Pour l'utiliser, mettez simplement Timer ("blahblah") au début d'une portée locale. Le temps écoulé sera imprimé à la fin de la portée:
for i in xrange(5):
timer = Timer("eigh()")
x = numpy.random.random((4000,4000));
x = (x+x.T)/2
numpy.linalg.eigh(x)
print i+1
timer = None
Il imprime:
1
eigh() elapsed: 10.13s
2
eigh() elapsed: 9.74s
3
eigh() elapsed: 10.70s
4
eigh() elapsed: 10.25s
5
eigh() elapsed: 11.28s
timer
n'est pas supprimée après le dernier appel, si un autre code suit après la for
boucle. Pour obtenir la dernière valeur du timer, il faut supprimer ou écraser timer
la for
boucle après la boucle, par exemple via timer = None
.
Mise à jour de la réponse d' Eli à Python 3:
class Timer(object):
def __init__(self, name=None, filename=None):
self.name = name
self.filename = filename
def __enter__(self):
self.tstart = time.time()
def __exit__(self, type, value, traceback):
message = 'Elapsed: %.2f seconds' % (time.time() - self.tstart)
if self.name:
message = '[%s] ' % self.name + message
print(message)
if self.filename:
with open(self.filename,'a') as file:
print(str(datetime.datetime.now())+": ",message,file=file)
Tout comme Eli, il peut être utilisé comme gestionnaire de contexte:
import time
with Timer('Count'):
for i in range(0,10_000_000):
pass
Production:
[Count] Elapsed: 0.27 seconds
Je l'ai également mis à jour pour imprimer les unités de temps rapportées (secondes) et couper le nombre de chiffres comme suggéré par Can, et avec la possibilité d'ajouter également à un fichier journal. Vous devez importer datetime pour utiliser la fonction de journalisation:
import time
import datetime
with Timer('Count', 'log.txt'):
for i in range(0,10_000_000):
pass
En m'appuyant sur les réponses de Stefan et d'Antonimmo, j'ai fini par mettre
def Tictoc():
start_stack = []
start_named = {}
def tic(name=None):
if name is None:
start_stack.append(time())
else:
start_named[name] = time()
def toc(name=None):
if name is None:
start = start_stack.pop()
else:
start = start_named.pop(name)
elapsed = time() - start
return elapsed
return tic, toc
dans un utils.py
module, et je l'utilise avec un
from utils import Tictoc
tic, toc = Tictoc()
Par ici
tic()
, toc()
et les imbriquer comme dans Matlabtic(1)
, toc(1)
ou tic('very-important-block')
, toc('very-important-block')
et minuteries avec des noms différents n'interférer(ici, toc n'imprime pas le temps écoulé, mais le renvoie.)
tic = time.time()
ettoc = time.time()
, alorsprint toc-tic, 'sec Elapsed'
comme les gens l'ont dit ci-dessous, cependant,timeit
c'est plus robuste.