¿Cómo puedo saber dónde está colgado mi script de python?

Así que estoy depurando mi progtwig de Python y he encontrado un error que hace que el progtwig se cuelgue, como en un bucle infinito. Ahora, tuve un problema con un bucle infinito antes, pero cuando colgué, pude matar el progtwig y Python emitió una excepción útil que me dijo dónde terminaba el progtwig cuando le envié el comando kill. Ahora, sin embargo, cuando el progtwig se cuelga y lo presiono, no se cancela pero continúa ejecutándose. ¿Hay alguna herramienta que pueda usar para localizar el teléfono? Soy nuevo en la creación de perfiles, pero por lo que sé, un generador de perfiles solo puede proporcionarle información sobre un progtwig que se ha completado con éxito. ¿O puedes usar un generador de perfiles para depurar tales problemas?

Supongamos que está ejecutando su progtwig como:

 python YOURSCRIPT.py 

Intente ejecutar su progtwig como:

 python -m trace --trace YOURSCRIPT.py 

Y tenga paciencia mientras se imprimen muchas cosas en la pantalla. Si tiene un bucle infinito, continuará por siempre (problema de detención). Si se queda atascado en alguna parte, la mayoría está atascado en E / S o es un punto muerto.

¡Guauu! Ya hay 5 respuestas y nadie ha sugerido lo más obvio y sencillo:

  1. Trate de encontrar un caso de prueba reproducible que cause el comportamiento colgante.
  2. Agregue el registro a su código. Esto puede ser tan básico como print "**010" , print "**020" , etc. salpicado a través de las áreas principales.
  3. Ejecutar código. Mira donde cuelga. ¿No puedes entender por qué? Añadir más registro. (Es decir, si entre ** 020 y ** 030, vaya y agregue ** 023, ** 025, ** 027, etc.)
  4. Goto 3.

Los niños en estos días con sus lujosos depuradores e IDE … A veces, los problemas de ingeniería se resuelven de la manera más simple con herramientas simples que brindan un poco más de información.

Si su progtwig es demasiado grande y complejo para ser viable para un solo paso con pdb o para imprimir cada línea con el módulo de rastreo, entonces podría intentar un truco desde mis días de progtwigción de juegos de 8 bits. Desde Python 2.5 en adelante, pdb tiene la capacidad de asociar código con un punto de interrupción mediante el commands comandos. Puede usar esto para imprimir un mensaje y continuar ejecutando:

 (Pdb) commands 1 (com) print "*** Breakpoint 1 ***" (com) continue (com) end (Pdb) 

Esto imprimirá un mensaje y continuará ejecutándose cuando se scope el punto de interrupción 1. Defina comandos similares para algunos otros puntos de interrupción.

Puede usar esto para hacer una especie de búsqueda binaria de su código. Adjunte puntos de interrupción en los lugares clave del código y ejecútelo hasta que cuelgue. Puede decir del último mensaje cuál fue el último punto de interrupción que golpeó. Luego puede mover los otros puntos de interrupción y volver a ejecutar para reducir el lugar en el código donde se cuelga. Enjuague y repita.

Incidentalmente, en los micros de 8 bits (Commodore 64, Spectrum, etc.) podría introducir un valor en una ubicación de registro para cambiar el color del borde alrededor de la pantalla. Solía ​​configurar algunos puntos de interrupción para hacer esto con diferentes colores, de modo que cuando se ejecutara el progtwig se mostraría un arco iris psicodélico hasta que se colgara, luego el borde cambiaría a un solo color que le indicaría cuál era el último punto de interrupción. También puede obtener una buena idea del rendimiento relativo de diferentes secciones de código por la cantidad de cada color en el arco iris. A veces echo de menos esa simplicidad en estas nuevas máquinas “Windows”.

Escribí un módulo que imprime hilos que cuelgan más de 10 segundos en un solo lugar. hanging_threads.py

Aquí hay un ejemplo de salida:

 -------------------- Thread 5588 -------------------- File "C:\python33\lib\threading.py", line 844, in _exitfunc t.join() File "C:\python33\lib\threading.py", line 743, in join self._block.wait() File "C:\python33\lib\threading.py", line 184, in wait waiter.acquire() 

Esto ocurre a la salida del hilo principal cuando se olvida de establecer otro hilo como demonio.

Es más fácil evitar estos problemas que depurarlos.

Primero: los bucles son muy, muy difíciles de bloquear en una situación en la que el bucle no termina. Muy duro.

Segundo: while bucles son relativamente fáciles de atascar en un bucle.

El primer paso es verificar cada bucle while para ver si debe ser un bucle while. A menudo puede reemplazar while construye con, y corregirá su problema repensando su bucle.

Si no puede reemplazar un bucle while con for , entonces simplemente debe demostrar que la expresión en la instrucción while debe cambiar cada vez que pasa por el bucle. Esto no es tan difícil de probar.

  1. Mira todas las condiciones en el bucle. Llama a este T.

  2. Mira todas las twigs lógicas en el cuerpo del bucle. ¿Hay alguna forma de atravesar el bucle sin realizar un cambio en la condición, T ?

    • ¿Sí? Ese es tu error. Esa ruta lógica es incorrecta.

    • ¿No? Excelente, ese bucle debe terminar.

Si su progtwig es un poco demasiado complejo para simplemente rastrear todas las funciones, puede intentar ejecutarlo y adjuntar manualmente un progtwig trazador como lptrace . Funciona un poco como strace : imprime cada función que hace su progtwig. Aquí está cómo llamarlo:

 python lptrace -p $STUCK_PROGRAM_PID 

Tenga en cuenta que lptrace requiere gdb para ejecutarse.

Nada como el buen viejo pdb

 import pdb pdb.run('my_method()',globals(),locals()) 

Luego simplemente presione (n) para ir al siguiente comando, (s) para ingresar. Vea los documentos para la referencia completa. Siga su progtwig paso a paso, y probablemente lo resolverá lo suficientemente rápido.

También puede probar http://code.activestate.com/recipes/576515-debugging-a-running-python-process-by-interrupting/ . Debería funcionar siempre que el proceso de Python no tenga señales enmascaradas, lo que suele ser el caso incluso si Ctrl-C no funciona.

No lo he usado, pero he escuchado que el IDE de Eric es bueno y tiene un buen depurador. Ese es también el único IDE que conozco que tiene un depurador para Python

Si su progtwig tiene más de un hilo, podría estar ignorando ctrl-c porque el hilo está conectado al controlador ctrl-c, pero el hilo en vivo (¿fuera de control?) Es sordo. El GIL (locking de intérprete global) en CPython significa que normalmente solo se puede ejecutar un subproceso a la vez. Creo que resolví mi (quizás) problema similar usando este

 i = 0 for t in threading.enumerate(): if i != 0:# and t.getName() != 'Thread-1': print t.getName() t._Thread__stop() i += 1 

Una vez que sepas los nombres de los hilos; Comience a volver a ejecutar su script y filtre hacia abajo, sin impedir que se aborten. i = 0 condicional evita que el hilo principal sea abortado.

Sugiero pasar y nombrar todos tus hilos; por ejemplo: Hilo (target = self.log_sequence_status, name = ‘log status’)

Este código se debe colocar al final del progtwig principal que inicia el proceso de ejecución

Guauu ! Parece que usted agregó tanto código de una sola vez sin probarlo que no puede decir qué código se agregó justo antes de que el progtwig comenzara a bloquearse … (la causa más probable del problema).

En serio, debe codificar en pequeños pasos y probar cada uno individualmente (idealmente haciendo TDD).

Para su problema exacto de detectar qué código de Python se está ejecutando y ctrl-c no funciona, intentaré una aproximación en bruto: ¿usó alguna, except: capturar todas las excepciones indistintamente? Si lo hizo en un bucle (y continúa el bucle después de administrar la excepción), es muy probable que ctrl-c no funcione: está atrapado por esta excepción. Cambie a except Exception: y ya no se debería capturar (hay otras posibilidades para que ctrl + c no funcione como la gestión de hilos, como sugirió otro póster, pero creo que la razón anterior es más probable).

excepción KeyboardInterrupt

 Raised when the user hits the interrupt key (normally Control-C or Delete). 

Durante la ejecución, una verificación de interrupciones se realiza regularmente. Las interrupciones escritas cuando una entrada de función incorporada () o raw_input () están esperando una entrada también generan esta excepción. La excepción se hereda de BaseException para no ser atrapada accidentalmente por el código que captura la excepción y, por lo tanto, evita que el intérprete salga.

 Changed in version 2.5: Changed to inherit from BaseException.