Je suis donc en train de déboguer mon programme python et j'ai rencontré un bogue qui le bloque, comme dans une boucle infinie. Auparavant, j'avais déjà eu un problème avec une boucle infinie auparavant, mais quand il a raccroché, je pouvais tuer le programme et python a généré une exception utile qui m'indiquait où le programme s'était terminé lorsque je lui avais envoyé la commande kill. Maintenant, cependant, quand le programme raccroche et que je le ctrl-c, il n’abandonne pas mais continue de fonctionner. Existe-t-il un outil que je peux utiliser pour localiser le blocage? Je suis novice en profilage, mais d'après ce que je sais, un profileur peut uniquement vous fournir des informations sur un programme qui s'est terminé avec succès. Ou pouvez-vous utiliser un profileur pour déboguer de tels problèmes?
Supposons que vous exécutez votre programme en tant que:
python YOURSCRIPT.py
Essayez d’exécuter votre programme en tant que:
python -m trace --trace YOURSCRIPT.py
Et avoir un peu de patience pendant que beaucoup de choses sont imprimées à l'écran. Si vous avez une boucle infinie, elle continuera à jamais (problème d’arrêt). Si elle se coince quelque part, vous êtes généralement bloqué sur les E/S ou vous vous retrouvez dans une impasse.
Hou la la! 5 réponses déjà et personne n'a suggéré le plus évident et simple:
print "**010"
, print "**020"
, etc. parsemé de zones principales.Les enfants de nos jours avec leurs débogueurs et IDE sophistiqués ... Parfois, les problèmes d'ingénierie sont résolus plus simplement avec des outils rudimentaires qui fournissent juste un peu plus d'informations.
Si votre programme est trop volumineux et complexe pour être viable pour un pas à pas avec pdb ou pour imprimer chaque ligne avec le module de suivi, vous pouvez essayer une astuce de ma période de programmation de jeux 8 bits. À partir de Python 2.5, pdb peut associer du code à un point d'arrêt à l'aide de la commande commands
. Vous pouvez utiliser ceci pour imprimer un message et continuer à courir:
(Pdb) commands 1
(com) print "*** Breakpoint 1 ***"
(com) continue
(com) end
(Pdb)
Ceci imprimera un message et continuera à s'exécuter lorsque le point d'arrêt 1 sera atteint. Définissez des commandes similaires pour quelques autres points d'arrêt.
Vous pouvez l'utiliser pour effectuer une sorte de recherche binaire de votre code. Attachez des points d'arrêt aux endroits clés du code et exécutez-le jusqu'à ce qu'il se bloque. Vous pouvez dire à partir du dernier message quel était le dernier point d'arrêt touché. Vous pouvez ensuite déplacer les autres points d'arrêt et recommencer pour réduire l'endroit dans le code où il se bloque. Rincer et répéter.
Incidemment, sur les micros 8 bits (Commodore 64, Spectrum, etc.), vous pouvez insérer une valeur dans un emplacement du registre pour modifier la couleur de la bordure autour de l'écran. J'avais l'habitude de configurer quelques points d'arrêt pour le faire avec différentes couleurs. Ainsi, lorsque le programme était lancé, il affichait un affichage psychédélique de Rainbow jusqu'à ce qu'il soit suspendu. La bordure devenait alors une couleur unique qui indiquait le dernier point d'arrêt. Vous pouvez également avoir une bonne idée de la performance relative des différentes sections de code en fonction de la quantité de chaque couleur dans l'arc-en-ciel. Parfois, cette simplicité me manque dans ces nouvelles machines "Windows".
J'ai écrit un module qui imprime les fils qui durent plus longtemps que 10 secondes à un endroit . accrocher_threads.py
Voici un exemple de sortie:
-------------------- 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()
Cela se produit à la sortie du thread principal lorsque vous oubliez de définir un autre thread en tant que démon.
Il est plus facile d'éviter ces blocages que de les déboguer.
Premièrement: les boucles for
sont très, très difficiles à bloquer dans une situation où la boucle ne se termine pas. Très dur.
Deuxièmement: les boucles while
sont relativement faciles à rester coincées dans une boucle.
La première étape consiste à vérifier chaque boucle while
pour voir s’il s’agit doit _ être une boucle while
. Souvent, vous pouvez remplacer les constructions while
par for
et vous corrigerez votre problème en repensant votre boucle.
Si vous ne pouvez pas remplacer une boucle while
par for
, vous devez simplement prouver que l'expression de l'instruction while
doit _ change à chaque fois dans la boucle. Ce n'est pas si difficile à prouver.
Regardez toutes les conditions de la boucle. Appelez ceci T.
Regardez toutes les branches logiques dans le corps de la boucle. Existe-t-il un moyen de parcourir la boucle sans modifier la condition T?
Oui? C'est ton bug. Ce chemin logique est faux.
Non? Excellent, cette boucle doit se terminer.
Si votre programme est un peu trop complexe pour tracer simplement toutes les fonctions, vous pouvez essayer de l'exécuter et d'y attacher manuellement un programme de suivi tel que lptrace . Cela fonctionne un peu comme strace
– il imprime toutes les fonctions appelées par votre programme. Voici comment l'appeler:
python lptrace -p $STUCK_PROGRAM_PID
Notez que lptrace nécessite gdb pour s'exécuter.
Vous pouvez également essayer http://code.activestate.com/recipes/576515-debugging-a-running-python-process-by-interrupting/ . Cela devrait fonctionner tant que le processus Python n'a pas de signaux masqués, ce qui est normalement le cas même si Ctrl-C ne fonctionne pas.
Rien de tel que le bon vieux pdb
import pdb
pdb.run('my_method()',globals(),locals())
Ensuite, appuyez simplement sur (n) pour passer à la commande suivante, dans laquelle vous devez entrer. voir la documentation pour la référence complète . Suivez votre programme étape par étape, et vous l'aurez compris assez rapidement.
i = 0
for t in threading.enumerate():
if i != 0:# and t.getName() != 'Thread-1':
print t.getName()
t._Thread__stop()
i += 1
Une fois que vous connaissez les noms des discussions; commencez à ré-exécuter votre script et filtrez-les pour ne pas les empêcher d'être abandonnés. i = 0 conditionnel empêche le thread principal d'être abandonné.
Je suggère de passer en revue et de nommer toutes vos discussions; tels que: Thread (target = self.log_sequence_status, name = 'log status')
Ce code doit être placé à la fin du programme principal qui lance le processus de fuite.
Je ne l'ai pas utilisé moi-même, mais j'ai entendu dire que le Eric IDE est bon et qu'il a un bon débogueur. C’est aussi le seul IDE que je connaisse qui ait un débogueur pour Python
Si votre programme a plus d'un thread, il est possible que ctrl-c soit ignoré, car l'un des threads est connecté au gestionnaire ctrl-c, mais le thread live (emballé?) En est sourd. Le verrou global d'interprète (GIL) dans CPython signifie que normalement, un seul thread ne peut être exécuté à la fois… .. Je pense avoir résolu mon problème similaire (peut-être) en utilisant this