El Proyecto Euler y otros concursos de codificación a menudo tienen un tiempo máximo para ejecutarse o las personas se jactan de lo rápido que se ejecuta su solución particular. Con Python, a veces los enfoques son un tanto torpes, es decir, agregar código de tiempo a __main__
.
¿Cuál es una buena manera de perfilar cuánto tiempo tarda un programa Python en ejecutarse?
python
performance
profiling
time-complexity
Chris Lawlor
fuente
fuente
Respuestas:
Python incluye un generador de perfiles llamado cProfile . No solo proporciona el tiempo total de ejecución, sino que también multiplica cada función por separado y le indica cuántas veces se llamó a cada función, lo que facilita determinar dónde debe realizar las optimizaciones.
Puede llamarlo desde su código, o desde el intérprete, así:
Aún más útil, puede invocar el cProfile cuando ejecuta un script:
Para hacerlo aún más fácil, hice un pequeño archivo por lotes llamado 'profile.bat':
Entonces todo lo que tengo que hacer es correr:
Y entiendo esto:
EDITAR: Enlace actualizado a un buen recurso de video de PyCon 2013 titulado Python Profiling
También a través de YouTube .
fuente
python -m cProfile -o <out.profile> <script>
), RunSnakeRun , invocado comorunsnake <out.profile>
es invaluable.cprofile
todavía se recomienda másprofile
.Hace un tiempo hice
pycallgraph
que genera una visualización a partir de su código Python. Editar: He actualizado el ejemplo para que funcione con 3.3, la última versión de este escrito.Después de
pip install pycallgraph
instalar e GraphViz , puede ejecutarlo desde la línea de comandos:O bien, puede perfilar partes particulares de su código:
Cualquiera de estos generará un
pycallgraph.png
archivo similar a la imagen a continuación:fuente
Traceback (most recent call last): /pycallgraph.py", line 90, in generate output.done() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 94, in done source = self.generate() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 143, in generate indent_join.join(self.generate_attributes()), File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 169, in generate_attributes section, self.attrs_from_dict(attrs), ValueError: zero length field name in format
sudo apt-get install graphviz
.Vale la pena señalar que usar el generador de perfiles solo funciona (de forma predeterminada) en el hilo principal, y no obtendrá ninguna información de otros hilos si los usa. Esto puede ser un poco un problema ya que no se menciona por completo en la documentación del generador de perfiles .
Si también desea perfilar hilos, querrá ver la
threading.setprofile()
función en los documentos.También puede crear su propia
threading.Thread
subclase para hacerlo:y usa esa
ProfiledThread
clase en lugar de la estándar. Puede darle más flexibilidad, pero no estoy seguro de que valga la pena, especialmente si está utilizando un código de terceros que no usaría su clase.fuente
target
función de Thread , que es lo quethreading.Thread.run()
ejecuta la llamada. Pero como dije en la respuesta, probablemente no valga la pena subclasificar Thread, ya que cualquier código de terceros no lo usará, y en su lugar lo usaráthreading.setprofile()
.El wiki de Python es una gran página para la creación de perfiles de recursos: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code
al igual que los documentos de Python: http://docs.python.org/library/profile.html
Como lo muestra Chris Lawlor, cProfile es una gran herramienta y se puede usar fácilmente para imprimir en la pantalla:
o para archivar:
PD> Si estás usando Ubuntu, asegúrate de instalar python-profile
Si sale al archivo, puede obtener visualizaciones agradables utilizando las siguientes herramientas
PyCallGraph: una herramienta para crear imágenes de gráficos de llamadas
instalar:
correr:
ver:
Puedes usar lo que quieras para ver el archivo png, usé gimp
Desafortunadamente a menudo obtengo
dot: graph es demasiado grande para mapas de bits de cairo-render. Escalando en 0.257079 para adaptarse
lo que hace que mis imágenes sean inusualmente pequeñas. Así que generalmente creo archivos svg:
PS> asegúrese de instalar graphviz (que proporciona el programa de puntos):
Gráficos alternativos usando gprof2dot a través de @maxy / @quodlibetor:
fuente
El comentario de @ Maxy sobre esta respuesta me ayudó lo suficiente como para pensar que merece su propia respuesta: ya tenía archivos .pstats generados por cProfile y no quería volver a ejecutar las cosas con pycallgraph, así que usé gprof2dot , y me volví bonita svgs:
y BLAM!
Utiliza punto (lo mismo que usa pycallgraph), por lo que la salida se ve similar. Sin embargo, tengo la impresión de que gprof2dot pierde menos información:
fuente
pwd
/gprof2dot/gprof2dot.py $ HOME / bin (o use ln -s $ PWD / gprof2dot / gprof2dot.py ~ / bin en la mayoría de los shells - el acento grave se toma como formato en primer lugar versión).ln
equivoco en el orden de los argumentos casi siempre.Me encontré con una herramienta útil llamada SnakeViz cuando investigaba este tema. SnakeViz es una herramienta de visualización de perfiles basada en la web. Es muy fácil de instalar y usar. La forma habitual en que lo uso es generar un archivo de estadísticas
%prun
y luego hacer análisis en SnakeViz.La técnica de visualización principal utilizada es el gráfico Sunburst como se muestra a continuación, en el que la jerarquía de las llamadas a funciones se organiza como capas de arcos e información de tiempo codificada en sus anchos angulares.
Lo mejor es que puedes interactuar con el gráfico. Por ejemplo, para acercar uno puede hacer clic en un arco, y el arco y sus descendientes se agrandarán como un nuevo resplandor solar para mostrar más detalles.
fuente
La forma más simple y rápida de encontrar a dónde va todo el tiempo.
Dibuja un gráfico circular en un navegador. La pieza más grande es la función del problema. Muy simple.
fuente
Creo que
cProfile
es excelente para crear perfiles, mientras quekcachegrind
es excelente para visualizar los resultados. Elpyprof2calltree
intermedio maneja la conversión del archivo.Para instalar las herramientas necesarias (en Ubuntu, al menos):
El resultado:
fuente
brew install qcachegrind
y substitude cada unokcachegrind
conqcachegrind
en la descripción de perfiles de éxito.export QT_X11_NO_MITSHM=1
También vale la pena mencionar el visor de volcado de cProfile de GUI RunSnakeRun . Le permite ordenar y seleccionar, haciendo zoom en las partes relevantes del programa. El tamaño de los rectángulos en la imagen es proporcional al tiempo empleado. Si pasa el mouse sobre un rectángulo, resalta esa llamada en la tabla y en todas partes del mapa. Cuando hace doble clic en un rectángulo, se acerca a esa parte. Le mostrará quién llama a esa porción y qué llama esa porción.
La información descriptiva es muy útil. Le muestra el código para ese bit que puede ser útil cuando se trata de llamadas de biblioteca incorporadas. Te dice qué archivo y qué línea encontrar el código.
También quiero señalar que el OP dijo 'perfilado' pero parece que se refería a 'tiempo'. Tenga en cuenta que los programas se ejecutarán más lentamente cuando se perfilen.
fuente
Recientemente creé atún para visualizar Python runtime e importar perfiles; Esto puede ser útil aquí.
Instalar con
Crear un perfil de tiempo de ejecución
o un perfil de importación (se requiere Python 3.7+)
Luego solo ejecuta atún en el archivo
fuente
Un buen módulo de creación de perfiles es line_profiler (llamado mediante el script kernprof.py). Se puede descargar aquí .
Entiendo que cProfile solo brinda información sobre el tiempo total empleado en cada función. Por lo tanto, las líneas individuales de código no están cronometradas. Este es un problema en la informática científica, ya que a menudo una sola línea puede llevar mucho tiempo. Además, como recuerdo, cProfile no captó el tiempo que pasaba en decir numpy.dot.
fuente
pprofile
line_profiler
(ya presentado aquí) también inspiradopprofile
, que se describe como:Proporciona granularidad de línea, ya que
line_profiler
es Python puro, se puede usar como un comando independiente o un módulo, e incluso puede generar archivos de formato callgrind que se pueden analizar fácilmente[k|q]cachegrind
.vprof
También hay vprof , un paquete de Python descrito como:
fuente
Hay muchas respuestas excelentes, pero usan la línea de comandos o algún programa externo para perfilar y / u ordenar los resultados.
Realmente eché de menos alguna forma de usar mi IDE (eclipse-PyDev) sin tocar la línea de comando o instalar nada. Asi que aqui esta.
Perfilado sin línea de comando
Ver documentos u otras respuestas para más información.
fuente
Siguiendo la respuesta de Joe Shaw sobre el código multiproceso que no funciona como se esperaba, me di cuenta de que el
runcall
método en cProfile es simplemente hacerself.enable()
yself.disable()
llama a la llamada de función perfilada, por lo que puede hacerlo usted mismo y tener el código que desee en el medio mínima interferencia con el código existente.fuente
cprofile.py
código fuente revela que eso es exactamente lo queruncall()
hace. Siendo más específico, después de crear una instancia de Perfil conprof = cprofile.Profile()
, llame inmediatamenteprof.disable()
, y luego simplemente agregueprof.enable()
yprof.disable()
llame alrededor de la sección de código que desea perfilar.En la fuente de Virtaal hay una clase y un decorador muy útiles que pueden facilitar la creación de perfiles (incluso para métodos / funciones específicos). La salida se puede ver muy cómodamente en KCacheGrind.
fuente
cProfile es excelente para la creación de perfiles rápidos, pero la mayoría de las veces me terminaba con los errores. La función runctx resuelve este problema al inicializar correctamente el entorno y las variables, espero que pueda ser útil para alguien:
fuente
Si desea hacer un generador de perfiles acumulativo, lo que significa ejecutar la función varias veces seguidas y ver la suma de los resultados.
puedes usar este
cumulative_profiler
decorador:es python> = 3.6 específico, pero puede eliminarlo
nonlocal
para que funcione en versiones anteriores.Ejemplo
perfilando la función
baz
baz
corrió 5 veces e imprimió esto:especificando la cantidad de veces
fuente
La solución solo para terminal (y la más simple), en caso de que todas esas UI sofisticadas no se instalen o ejecuten:
ignórelas por
cProfile
completo y reemplácelaspyinstrument
, que recolectará y mostrará el árbol de llamadas justo después de la ejecución.Instalar en pc:
Perfil y resultado de visualización:
Funciona con python2 y 3.
[EDITAR] La documentación de la API, para perfilar solo una parte del código, se puede encontrar aquí .
fuente
Mi forma es usar yappi ( https://github.com/sumerc/yappi ). Es especialmente útil combinado con un servidor RPC donde (incluso solo para la depuración) registra el método para iniciar, detener e imprimir información de perfil, por ejemplo, de esta manera:
Luego, cuando su programa funcione, puede iniciar el generador de perfiles en cualquier momento llamando al
startProfiler
método RPC y volcar la información de perfil en un archivo de registro llamandoprintProfiler
(o modificar el método rpc para devolverlo al llamante) y obtener dicha salida:Puede que no sea muy útil para scripts cortos, pero ayuda a optimizar los procesos de tipo servidor, especialmente dado que el
printProfiler
método puede llamarse varias veces a lo largo del tiempo para perfilar y comparar, por ejemplo, diferentes escenarios de uso del programa.En las versiones más recientes de yappi, el siguiente código funcionará:
fuente
def printProfiler(): if not yappi_available: return stats = yappi.get_func_stats() stats.print_all(columns={0:("name",90), 1:("ncall", 5), 2:("tsub", 8), 3:("ttot", 8), 4:("tavg",8)})
(OK después de intentar un par de veces para insertar el bloque de código en el comentario que di). Esto es increíblemente difícil para un sitio de preguntas y respuestas orientado a la programación. )Una nueva herramienta para manejar la creación de perfiles en Python es PyVmMonitor: http://www.pyvmmonitor.com/
Tiene algunas características únicas como
Nota: es comercial, pero gratis para código abierto.
fuente
gprof2dot_magic
Función mágica para
gprof2dot
perfilar cualquier declaración de Python como un gráfico DOT en JupyterLab o Jupyter Notebook.Repo de GitHub: https://github.com/mattijn/gprof2dot_magic
instalación
Asegúrate de tener el paquete Python
gprof2dot_magic
.Sus dependencias
gprof2dot
ygraphviz
se instalarán tambiénuso
Para habilitar la función mágica, primero cargue el
gprof2dot_magic
móduloy luego perfile cualquier declaración de línea como un gráfico DOT como tal:
fuente
https://github.com/amoffat/Inspect-Shell
Podrías usar eso (y tu reloj de pulsera).
fuente
Para agregar a https://stackoverflow.com/a/582337/1070617 ,
Escribí este módulo que le permite usar cProfile y ver su salida fácilmente. Más aquí: https://github.com/ymichael/cprofilev
Consulte también: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html sobre cómo dar sentido a las estadísticas recopiladas.
fuente
Dependerá de lo que quiera ver de los perfiles. Las métricas de tiempo simples pueden ser dadas por (bash).
Incluso '/ usr / bin / time' puede generar métricas detalladas utilizando el indicador '--verbose'.
Para verificar las métricas de tiempo proporcionadas por cada función y comprender mejor cuánto tiempo se dedica a las funciones, puede usar el cProfile incorporado en python.
Al entrar en métricas más detalladas como el rendimiento, el tiempo no es la única métrica. Puede preocuparse por la memoria, los subprocesos, etc.
Opciones de creación de perfiles:
1. line_profiler es otro generador de perfiles que se usa comúnmente para averiguar métricas de temporización línea por línea.
2. memory_profiler es una herramienta para perfilar el uso de memoria.
3. heapy (del proyecto Guppy) Perfil de cómo se utilizan los objetos en el montón.
Estos son algunos de los más comunes que suelo usar. Pero si desea obtener más información, intente leer este libro. Es un libro bastante bueno para comenzar teniendo en cuenta el rendimiento. Puede pasar a temas avanzados sobre el uso de Python compilado Cython y JIT (Just-in-time).
fuente
Con un generador de perfiles estadísticos como Austin , no se requiere instrumentación, lo que significa que puede obtener datos de perfiles de una aplicación Python simplemente con
La salida en bruto no es muy útil, pero puede canalizar eso a flamegraph.pl para obtener una representación gráfica de la llama de esos datos que le da un desglose de dónde se está gastando el tiempo (medido en microsegundos de tiempo real).
fuente
Para obtener estadísticas de perfil rápidas en una notebook IPython. Uno puede integrar line_profiler y memory_profiler directamente en sus cuadernos.
Otro paquete útil es Pympler . Es un poderoso paquete de creación de perfiles que es capaz de rastrear clases, objetos, funciones, pérdidas de memoria, etc. Ejemplos a continuación, Documentos adjuntos.
¡Consíguelo!
¡Cárgalo!
Úsalo!
%hora
Da:
%cronométralo
% poda
Da:
% memit
Da:
% lprun
Da:
sys.getsizeof
Devuelve el tamaño de un objeto en bytes.
asizeof () de pympler
pympler.asizeof se puede usar para investigar cuánta memoria consumen ciertos objetos de Python. A diferencia de sys.getsizeof, asizeof dimensiona objetos de forma recursiva
rastreador de pympler
Realiza un seguimiento de la vida útil de una función.
El paquete Pympler consta de una gran cantidad de funciones de alta utilidad para perfilar el código. Todo lo cual no puede ser cubierto aquí. Consulte la documentación adjunta para ver las implementaciones detalladas del perfil.
Pympler doc
fuente
También hay un generador de perfiles estadísticos llamado
statprof
. Es un generador de perfiles de muestreo, por lo que agrega una sobrecarga mínima a su código y proporciona tiempos basados en líneas (no solo en función). Es más adecuado para aplicaciones suaves en tiempo real como juegos, pero puede tener menos precisión que cProfile.La versión en pypi es un poco antigua, por lo que puede instalarla
pip
especificando el repositorio git :Puedes ejecutarlo así:
Ver también https://stackoverflow.com/a/10333592/320036
fuente
Acabo de desarrollar mi propio generador de perfiles inspirado en pypref_time:
https://github.com/modaresimr/auto_profiler
Al agregar un decorador, mostrará un árbol de funciones que consumen mucho tiempo
@Profiler(depth=4, on_disable=show)
Ejemplo
Salida de ejemplo
fuente
Cuando no soy root en el servidor, uso lsprofcalltree.py y ejecuto mi programa así:
Luego puedo abrir el informe con cualquier software compatible con callgrind, como qcachegrind
fuente