example python matlab

example - python timer



tic, funciones toc analógicas en Python (10)

Acabo de crear un módulo [tictoc.py] para lograr tocs tic 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.

¿Cuál es el mejor análogo de las funciones de MATLAB tic y toc ( http://www.mathworks.com/help/techdoc/ref/tic.html ) en Python?


Actualizando la respuesta de Eli a Python 3:

class Timer(object): def __init__(self, name=None): self.name = name def __enter__(self): self.tstart = time.time() def __exit__(self, type, value, traceback): message = ''Elapsed: %s'' % (time.time() - self.tstart) if self.name: message = ''[%s] '' % self.name + message print(message)


Además del timeit que ThiefMaster mencionó, una forma simple de hacerlo es justo (después de importar el 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 usar como administrador de contexto:

with Timer(''foo_stuff''): # do some foo # do some stuff

A veces encuentro que esta técnica es más conveniente que timeit , todo depende de lo que quieras medir.


Cambié un poco la respuesta de @Eli Bendersky para usar el ctor __init__() y dtor __del__() para hacer el cronometraje, para que se pueda usar más cómodamente 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 usar, 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


Eche un vistazo al módulo timeit . No es realmente equivalente, pero si el código que desea medir está dentro de una función, puede usarlo fácilmente.


El mejor análogo absoluto 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()


Esto también se puede hacer usando un contenedor. Manera muy general de mantener el tiempo.

El contenedor de este código de ejemplo ajusta 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()


Generalmente, el %time de IPython, %timeit , %prun y %lprun (si uno tiene instalado line_profiler ) satisfacen mis necesidades de perfil bastante bien. Sin embargo, surgió un caso de uso para la funcionalidad tipo tic-toc cuando traté de perfilar cálculos que fueron conducidos de forma interactiva, es decir, por el movimiento del mouse del usuario en una GUI. Tenía ganas de enviar y toc tic deseados en las fuentes, mientras que la prueba interactiva sería la manera más rápida de revelar los cuellos de botella. Fui con la clase Timer 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 un inconveniente para algunos editores y confunde el sistema de control de versiones. Además, puede existir la necesidad de medir el tiempo entre puntos en diferentes funciones, lo que no funcionaría con la instrucción with . Después de probar mucho de la inteligencia de Python, aquí está la solución simple que encontré que funcionó 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 los tiempos de inicio en una pila, funcionará correctamente para múltiples niveles de tic y toc . También permite cambiar la cadena de formato de la instrucción toc para mostrar información adicional, lo que me gustó de la clase Timer de Eli.

Por alguna razón, me preocupé por la sobrecarga de una implementación pura de Python, así que probé un módulo de extensión C también:

#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 límites por brevedad. Si bien tictoc.res() arroja una resolución de aproximadamente 50 nanosegundos en mi sistema, descubrí que el jitter de medir cualquier enunciado de Python es fácilmente del orden de los 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 enfoque de tic-toc está prácticamente limitada a los bloques de código que tardan más de 10 microsegundos en ejecutarse. Debajo de eso, se requieren estrategias de promedio como en timeit para obtener una medición fiel.


Sobre la base de 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 módulo utils.py , y lo uso con un

from utils import Tictoc tic, toc = Tictoc()

De esta manera

  • simplemente puede usar tic() , toc() y anidarlos como en Matlab
  • alternativamente, puede nombrarlos: tic(1) , toc(1) o tic(''very-important-block'') , toc(''very-important-block'') y los temporizadores con nombres diferentes no interferirán
  • importarlos de esta manera evita la interferencia entre los módulos que lo usan.

(Aquí toc no imprime el tiempo transcurrido, sino que lo devuelve).


Tenía la misma pregunta cuando migré a Python desde Matlab. Con la ayuda de este hilo pude construir un análogo exacto de las funciones Matlab tic() y toc() . Simplemente inserte el siguiente código en la parte superior de su 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)

¡Eso es! Ahora estamos listos para usar plenamente 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í, podría crear otra instancia del TicTocGenerator para realizar un seguimiento de las operaciones múltiples, o simplemente para TicTocGenerator cosas de manera diferente. Por ejemplo, al cronometrar un guión, ahora podemos cronometrar cada parte del guión por separado, así como el guión completo. (Proporcionaré 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 sincronizar dos cosas por separado: en el siguiente ejemplo, calculamos el tiempo del guión total y las 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 usar 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.