¿Hay alguna forma sencilla de hacer un benchmark con el script de python?

Usualmente uso time comando de shell. Mi propósito es probar si los datos son pequeños, medianos, grandes o muy grandes, el tiempo y el uso de la memoria.

¿Alguna herramienta para linux o simplemente python para hacer esto?

Eche un vistazo a timeit , el generador de perfiles de python y pycallgraph .

cronométralo

 def test(): """Stupid test function""" lst = [] for i in range(100): lst.append(i) if __name__ == '__main__': import timeit print(timeit.timeit("test()", setup="from __main__ import test")) 

Esencialmente, puede pasarle el código de Python como un parámetro de cadena, y se ejecutará en la cantidad de veces especificada e imprime el tiempo de ejecución. Los bits importantes de la documentación:

timeit.timeit(stmt='pass', setup='pass', timer=, number=1000000)

Cree una instancia de Timer con la instrucción dada, el código de configuración y la función del temporizador y ejecute su método timeit con ejecuciones numéricas .

… y:

Timer.timeit(number=1000000)

Número de tiempo de ejecuciones de la statement principal. Esto ejecuta la instrucción de configuración una vez, y luego devuelve el tiempo que lleva ejecutar la instrucción principal varias veces, medido en segundos como un flotador. El argumento es el número de veces que pasa a través del bucle, por defecto a un millón. La statement principal, la instrucción de configuración y la función de temporizador que se utilizará se pasan al constructor.

Nota

De forma predeterminada, timeit temporalmente la garbage collection de garbage collection durante el tiempo. La ventaja de este enfoque es que hace que los tiempos independientes sean más comparables. Esta desventaja es que GC puede ser un componente importante del desempeño de la función que se está midiendo. Si es así, GC se puede volver a habilitar como la primera statement en la cadena de configuración . Por ejemplo:

timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()

Perfilado

El perfil te dará una idea mucho más detallada de lo que está pasando. Aquí está el “ejemplo instantáneo” de los documentos oficiales :

 import cProfile import re cProfile.run('re.compile("foo|bar")') 

Lo que te dará:

  197 function calls (192 primitive calls) in 0.002 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.001 0.001 :1() 1 0.000 0.000 0.001 0.001 re.py:212(compile) 1 0.000 0.000 0.001 0.001 re.py:268(_compile) 1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset) 1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset) 4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction) 3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile) 

Ambos módulos deberían darle una idea sobre dónde buscar cuellos de botella.

Además, para familiarizarse con la salida del profile , consulte esta publicación.

pycallgraph

Este módulo utiliza graphviz para crear gráficos de llamadas como los siguientes:

ejemplo de callgraph

Puede ver fácilmente qué rutas consumieron más tiempo por color. Puede crearlos usando la API de pycallgraph, o usando un script empaquetado:

 pycallgraph graphviz -- ./mypythonscript.py 

Sin embargo, la sobrecarga es bastante considerable. Por lo tanto, para los procesos de larga ejecución, la creación del gráfico puede llevar algún tiempo.

Uso un simple decorador para cronometrar la función.

 def st_time(func): """ st decorator to calculate the total time of a func """ def st_func(*args, **keyArgs): t1 = time.time() r = func(*args, **keyArgs) t2 = time.time() print "Function=%s, Time=%s" % (func.__name__, t2 - t1) return r return st_func 

El módulo timeit era lento y extraño, así que escribí esto:

 def timereps(reps, func): from time import time start = time() for i in range(0, reps): func() end = time() return (end - start) / reps 

Ejemplo:

 import os listdir_time = timereps(10000, lambda: os.listdir('/')) print "python can do %d os.listdir('/') per second" % (1 / listdir_time) 

Para mí, dice:

 python can do 40925 os.listdir('/') per second 

Este es un tipo primitivo de evaluación comparativa, pero es lo suficientemente bueno.

Por lo general, hago un time ./script.py rápido time ./script.py para ver cuánto tiempo lleva. Sin embargo, eso no muestra la memoria, al menos no como predeterminado. Puede usar /usr/bin/time -v ./script.py para obtener mucha información, incluido el uso de la memoria.

Echa un vistazo a la nariz y a uno de sus complementos, este en particular.

Una vez instalado, nose es un script en su ruta, y puede llamar a un directorio que contiene algunos scripts de python:

 $: nosetests 

Esto buscará en todos los archivos de python en el directorio actual y ejecutará cualquier función que reconozca como prueba: por ejemplo, reconoce cualquier función con la palabra test_ en su nombre como prueba.

Así que puedes crear un script de python llamado test_yourfunction.py y escribir algo como esto en él:

 $: cat > test_yourfunction.py def test_smallinput(): yourfunction(smallinput) def test_mediuminput(): yourfunction(mediuminput) def test_largeinput(): yourfunction(largeinput) 

Entonces tienes que correr

 $: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py 

y para leer el archivo de perfil, usa esta línea de python:

 python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)" 

Perfil de memoria para todas sus necesidades de memoria.

https://pypi.python.org/pypi/memory_profiler

Ejecutar una instalación pip:

 pip install memory_profiler 

Importar la biblioteca:

 import memory_profiler 

Agrega un decorador al elemento que deseas perfilar:

 @profile def my_func(): a = [1] * (10 ** 6) b = [2] * (2 * 10 ** 7) del b return a if __name__ == '__main__': my_func() 

Ejecuta el código:

 python -m memory_profiler example.py 

Recibe la salida:

  Line # Mem usage Increment Line Contents ============================================== 3 @profile 4 5.97 MB 0.00 MB def my_func(): 5 13.61 MB 7.64 MB a = [1] * (10 ** 6) 6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7) 7 13.61 MB -152.59 MB del b 8 13.61 MB 0.00 MB return a 

Los ejemplos son de los documentos, vinculados arriba.

Tenga cuidado, el timeit es muy lento, toma 12 segundos en mi procesador mediano para simplemente inicializar (o tal vez ejecutar la función). puedes probar esta respuesta aceptada

 def test(): lst = [] for i in range(100): lst.append(i) if __name__ == '__main__': import timeit print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second 

Por algo simple usaré time , en mi PC devolverá el resultado 0.0

 import time def test(): lst = [] for i in range(100): lst.append(i) t1 = time.time() test() result = time.time() - t1 print(result) # 0.000000xxxx 

La forma fácil de probar rápidamente cualquier función es usar esta syntax: %timeit my_code

Por ejemplo :

 %timeit a = 1 13.4 ns ± 0.781 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)