¿Cuál es el equivalente en Python de las funciones tic y toc de Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
entonces print toc-tic
.
¿Cuál es el equivalente en Python de las funciones tic y toc de Matlab ?
tic = timeit.default_timer(); (U,S,V) = np.linalg.svd(A); toc = timeit.default_timer()
entonces print toc-tic
.
Respuestas:
Aparte de lo timeit
que ThiefMaster mencionó, una forma sencilla de hacerlo es simplemente (después de importar time
):
t = time.time()
# do stuff
elapsed = time.time() - t
Tengo una clase de ayuda que me gusta usar:
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))
Se puede utilizar como administrador de contexto:
with Timer('foo_stuff'):
# do some foo
# do some stuff
A veces encuentro esta técnica más conveniente que timeit
... todo depende de lo que quieras medir.
time
comando Unix para medir los tiempos de ejecución de los programas desde siempre, y este método replica esto dentro del código Python. No veo nada malo en ello, siempre que sea la herramienta adecuada para el trabajo. timeit
no siempre es eso, y un generador de perfiles es una solución mucho más pesada para la mayoría de las necesidades
print 'Elapsed: %.2f seconds % (time.time() - self.tstart)'
. Es difícil de entender sin% .2f. Gracias por la gran idea.
elapsed = t - time.time()
, en lugar de elapsed = time.time() - t
. En este último transcurrido será negativo. Sugerí este cambio como una edición.
elapsed = time.time() - t
es la forma que siempre da un valor positivo.
Tuve la misma pregunta cuando migré a Python desde Matlab. Con la ayuda de este hilo pude construir un análogo exacto de Matlab tic()
y toc()
funciones. Simplemente inserte el siguiente código en la parte superior de su secuencia de comandos.
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)
¡Eso es! Ahora estamos listos para usar completamente tic()
y toc()
al igual que en Matlab. Por ejemplo
tic()
time.sleep(5)
toc() # returns "Elapsed time: 5.00 seconds."
En realidad, esto es más versátil que las funciones integradas de Matlab. Aquí, puede crear otra instancia de TicTocGenerator
para realizar un seguimiento de múltiples operaciones, o simplemente para cronometrar las cosas de manera diferente. Por ejemplo, mientras cronometramos un guión, ahora podemos cronometrar cada parte del guión por separado, así como todo el guión. (Daré un ejemplo concreto)
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)
Ahora debería poder cronometrar dos cosas distintas: en el siguiente ejemplo, cronometramos el guión total y partes de un guión por separado.
tic()
time.sleep(5)
tic2()
time.sleep(3)
toc2() # returns "Elapsed time 2: 5.00 seconds."
toc() # returns "Elapsed time: 8.00 seconds."
En realidad, ni siquiera necesita usarlo tic()
cada vez. Si tiene una serie de comandos que desea cronometrar, puede escribir
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...
Espero que esto sea útil.
La mejor analogía absoluta de tic y toc sería simplemente definirlos 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"
Entonces puedes usarlos como:
tic()
# do stuff
toc()
tic
y toc
, que Matlab admite. Se necesitaría un poco más de sofisticación.
import time
exterior de ambas funciones, ya que potencialmente puede llevar bastante tiempo.
tic
presionar y salir toc
de ella.
timeit.default_timer()
es mejor que time.time()
porque time.clock()
podría ser más apropiado según el sistema operativo
Por lo general, IPython de %time
, %timeit
, %prun
y %lprun
(si se ha line_profiler
instalado) satisfacer mis necesidades de perfiles bastante bien. Sin embargo, tic-toc
surgió un caso de uso para una funcionalidad similar a la de cuando traté de perfilar cálculos que eran impulsados interactivamente, es decir, por el movimiento del mouse del usuario en una GUI. Me sentí como el correo basura tic
s y toc
s en las fuentes mientras que las pruebas de forma interactiva sería la forma más rápida para revelar los cuellos de botella. Fui con la Timer
clase de Eli Bendersky , pero no estaba del todo contento, ya que requería que cambiara la sangría de mi código, lo que puede ser inconveniente en algunos editores y confunde el sistema de control de versiones. Además, puede ser necesario medir el tiempo entre puntos en diferentes funciones, lo que no funcionaría con elwith
declaración. Después de probar mucha inteligencia de Python, aquí está la solución simple que encontré que funcionaba mejor:
from time import time
_tstart_stack = []
def tic():
_tstart_stack.append(time())
def toc(fmt="Elapsed: %s s"):
print fmt % (time() - _tstart_stack.pop())
Dado que esto funciona presionando las horas de inicio en una pila, funcionará correctamente para múltiples niveles de tic
sy toc
s. También permite cambiar la cadena de formato de la toc
declaración para mostrar información adicional, que me gustó de la Timer
clase de Eli .
Por alguna razón, me preocupó la sobrecarga de una implementación de Python pura, así que también probé un módulo de extensión de 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);
}
Esto es para MacOSX, y he omitido el código para verificar si lvl
está fuera de los límites por brevedad. Si bien tictoc.res()
produce una resolución de aproximadamente 50 nanosegundos en mi sistema, descubrí que el jitter de medir cualquier declaración de Python está fácilmente en el rango de microsegundos (y mucho más cuando se usa desde IPython). En este punto, la sobrecarga de la implementación de Python se vuelve insignificante, por lo que se puede usar con la misma confianza que la implementación de C.
Descubrí que la utilidad del tic-toc
enfoque-está prácticamente limitada a bloques de código que tardan más de 10 microsegundos en ejecutarse. Por debajo de eso, timeit
se requieren estrategias de promediado como en para obtener una medición fiel.
Puede usar tic
y toc
desde ttictoc
. Instalarlo con
pip install ttictoc
Y simplemente impórtelos en su script de la siguiente manera
from ttictoc import tic,toc
tic()
# Some code
print(toc())
Acabo de crear un módulo [tictoc.py] para lograr tic tocs anidados, que es lo que hace Matlab.
from time import time
tics = []
def tic():
tics.append(time())
def toc():
if len(tics)==0:
return None
else:
return time()-tics.pop()
Y funciona de esta manera:
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()
Espero que ayude.
Eche un vistazo al timeit
módulo. No es realmente equivalente, pero si el código que desea cronometrar está dentro de una función, puede usarlo fácilmente.
timeit
es mejor para los puntos de referencia. Ni siquiera tiene que ser una función única, puede pasar declaraciones abritamente complejas.
pip install easy-tictoc
En el código:
from tictoc import tic, toc
tic()
#Some code
toc()
Descargo de responsabilidad: soy el autor de esta biblioteca.
Esto también se puede hacer usando una envoltura. Manera muy general de llevar el tiempo.
El contenedor en este código de ejemplo envuelve cualquier función e imprime la cantidad de tiempo necesaria para ejecutar la función:
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()
Cambié un poco la respuesta de @Eli Bendersky para usar ctor __init__()
y dtor __del__()
para hacer el tiempo, de modo que pueda usarse de manera más conveniente sin sangrar el código original:
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)
Para usarlo, simplemente ponga Timer ("blahblah") al comienzo de algún ámbito local. El tiempo transcurrido se imprimirá al final del alcance:
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
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
no se elimina después de la última llamada, si algún otro código sigue después del for
ciclo. Para obtener el último valor del temporizador, se debe eliminar o sobrescribir el timer
después del for
ciclo, por ejemplo, a través de timer = None
.
Actualizando la respuesta de Eli a 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)
Al igual que Eli, se puede utilizar como administrador de contexto:
import time
with Timer('Count'):
for i in range(0,10_000_000):
pass
Salida:
[Count] Elapsed: 0.27 seconds
También lo he actualizado para imprimir las unidades de tiempo reportadas (segundos) y recortar el número de dígitos como sugiere Can, y con la opción de agregar también a un archivo de registro. Debe importar la fecha y la hora para usar la función de registro:
import time
import datetime
with Timer('Count', 'log.txt'):
for i in range(0,10_000_000):
pass
Basándome en las respuestas de Stefan y antonimmo, terminé poniendo
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
en un utils.py
módulo, y lo uso con un
from utils import Tictoc
tic, toc = Tictoc()
De esta manera
tic()
,toc()
y nido de ellos como en Matlabtic(1)
, toc(1)
o tic('very-important-block')
, toc('very-important-block')
y temporizadores con diferentes nombres no interferirá(aquí toc no imprime el tiempo transcurrido, pero lo devuelve).
tic = time.time()
ytoc = time.time()
,print toc-tic, 'sec Elapsed'
como la gente ha dicho a continuación,timeit
es más robusto.