Entiendo el concepto de lo que timeit
hace pero no estoy seguro de cómo implementarlo en mi código.
¿Cómo puedo comparar dos funciones, digamos insertion_sort
y tim_sort
, con timeit
?
La forma en que funciona timeit es ejecutar el código de configuración una vez y luego realizar llamadas repetidas a una serie de declaraciones. Por lo tanto, si desea probar la clasificación, es necesario tener cuidado para que una pasada en una ordenación en el lugar no afecte a la siguiente pasada con datos ya ordenados (eso, por supuesto, haría que el Timsort realmente brille porque funciona mejor) cuando los datos ya están parcialmente ordenados).
Aquí hay un ejemplo de cómo configurar una prueba para ordenar:
>>> 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
Tenga en cuenta que la serie de declaraciones hace una copia nueva de los datos sin clasificar en cada pase.
Además, tenga en cuenta la técnica de sincronización de ejecutar el conjunto de mediciones siete veces y mantener solo el mejor momento; esto realmente puede ayudar a reducir las distorsiones de medición debidas a otros procesos que se ejecutan en su sistema.
Esos son mis consejos para usar Timeit correctamente. Espero que esto ayude :-)
timsort(a)
y tome la diferencia :-).repeat(7,1000)
ya lo haces (usando la misma semilla)! Entonces su solución es IMO perfecta..repeat(7, 1000)
vs.repeat(2, 3500)
vs.repeat(35, 200
) debería depender de cómo el error debido a la carga del sistema se compara con el error debido a la variabilidad de entrada. En el caso extremo, si su sistema está siempre bajo una carga pesada, y ve una cola larga y delgada a la izquierda de la distribución del tiempo de ejecución (cuando lo atrapa en un estado inactivo raro), incluso podría.repeat(7000,1)
ser más útil que.repeat(7,1000)
si no puede presupuestar más de 7000 ejecuciones.Si desea usar
timeit
en una sesión interactiva de Python, hay dos opciones convenientes:Use el shell de IPython . Cuenta con la conveniente
%timeit
función especial:En un intérprete estándar de Python, puede acceder a las funciones y otros nombres que definió anteriormente durante la sesión interactiva importándolos desde
__main__
la declaración de configuración:fuente
from __main__ import f
técnica. No creo que esto sea tan conocido como debería ser. Es útil en casos como este donde se está cronometrando una llamada a una función o método. En otros casos (cronometrar una serie de pasos), es menos útil porque introduce sobrecarga de llamadas de función.%timeit f(x)
sys._getframe(N).f_globals
) deberían haber sido los predeterminados desde el principio.Te contaré un secreto: la mejor manera de usarlo
timeit
es en la línea de comando.En la línea de comando,
timeit
realiza un análisis estadístico adecuado: le indica cuánto tiempo tomó la ejecución más corta. Esto es bueno porque todo error en el tiempo es positivo. Entonces, el menor tiempo tiene el menor error. ¡No hay forma de obtener un error negativo porque una computadora nunca puede calcular más rápido de lo que puede calcular!Entonces, la interfaz de línea de comandos:
Eso es bastante simple, ¿eh?
Puedes configurar cosas:
¡lo cual también es útil!
Si desea varias líneas, puede usar la continuación automática del shell o usar argumentos separados:
Eso da una configuración de
y tiempos
Si desea tener secuencias de comandos más largas, puede sentirse tentado a moverse
timeit
dentro de una secuencia de comandos de Python. Sugiero evitar eso porque el análisis y el tiempo son simplemente mejores en la línea de comando. En cambio, tiendo a hacer scripts de shell:Esto puede tardar un poco más debido a las múltiples inicializaciones, pero normalmente eso no es gran cosa.
Pero que pasa si quieres usar
timeit
dentro de tu módulo?Bueno, la forma simple es hacer:
y eso te da acumulativo ( no mínimo!) para ejecutar ese número de veces.
Para obtener un buen análisis, use
.repeat
y tome el mínimo:Normalmente debe combinar esto con en
functools.partial
lugar delambda: ...
reducir los gastos generales. Por lo tanto, podría tener algo como:También puedes hacer:
lo que le daría algo más cercano a la interfaz desde la línea de comandos, pero de una manera mucho menos genial. Le
"from __main__ import ..."
permite usar el código de su módulo principal dentro del entorno artificial creado portimeit
.Vale la pena señalar que este es un envoltorio conveniente
Timer(...).timeit(...)
y, por lo tanto, no es particularmente bueno en el momento. Yo personalmente prefiero usarTimer(...).repeat(...)
como he mostrado anteriormente.Advertencias
Hay algunas advertencias
timeit
que se mantienen en todas partes.Los gastos generales no se contabilizan. Digamos que quiere tiempo
x += 1
, para averiguar cuánto tiempo lleva la suma:Bueno, es que no 0,0476 mu s. Solo sabes que es menos que eso. Todo error es positivo.
Así que trata de encontrar gastos generales puros :
¡Es un buen 30% de gastos generales solo por el tiempo! Esto puede sesgar masivamente los tiempos relativos. Pero sólo se preocupaba por las añadiendo tiempos; los tiempos de búsqueda
x
también deben incluirse en los gastos generales:La diferencia no es mucho mayor, pero está ahí.
Los métodos de mutación son peligrosos.
¡Pero eso está completamente mal!
x
es la lista vacía después de la primera iteración. Deberá reinicializar:Pero entonces tienes muchos gastos generales. Cuenta eso por separado.
Tenga en cuenta que restar la sobrecarga es razonable aquí solo porque la sobrecarga es una fracción pequeña del tiempo.
Para su ejemplo, vale la pena señalar que tanto el orden de inserción como el orden de tiempo tienen comportamientos de tiempo completamente inusuales para las listas ya ordenadas. Esto significa que necesitará un
random.shuffle
tipo intermedio si desea evitar arruinar sus tiempos.fuente
timeit
de un programa pero que funciona de la misma manera que la línea de comandos. .timeit
ejecuta unapass
declaración cuando no se dan argumentos, lo que, por supuesto, lleva algún tiempo. Si no se da ningún argumento,pass
se no se ejecutan, por lo que resta de algunos0.014
usecs de cada momento sería incorrecto.Si desea comparar dos bloques de código / funciones rápidamente, puede hacer lo siguiente:
fuente
Creo que la forma más fácil de usar timeit es desde la línea de comandos:
Dado test.py :
tiempo de ejecución así:
fuente
Para mí, esta es la forma más rápida:
fuente
fuente
Esto funciona muy bien:
fuente
permite configurar el mismo diccionario en cada uno de los siguientes y probar el tiempo de ejecución.
El argumento de configuración es básicamente configurar el diccionario
El número es para ejecutar el código 1000000 veces. No es la configuración sino el stmt
Cuando ejecuta esto, puede ver que el índice es mucho más rápido que get. Puede ejecutarlo varias veces para ver.
El código básicamente trata de obtener el valor de c en el diccionario.
Aquí están mis resultados, los suyos serán diferentes.
por índice: 0.20900007452246427
por get: 0.54841166886888
fuente
simplemente pase su código completo como argumento de tiempo:
fuente
fuente
gc.enable()
?El módulo timeit incorporado funciona mejor desde la línea de comandos de IPython.
Para cronometrar funciones desde un módulo:
fuente
Ejemplo de cómo usar el intérprete REPL de Python con una función que acepta parámetros.
fuente
Crearía dos funciones y luego ejecutaría algo similar a esto. Tenga en cuenta que desea elegir el mismo número de ejecución / ejecución para comparar manzana con manzana.
Esto fue probado bajo Python 3.7.
Aquí está el código para facilitar la copia.
fuente