2009-12-06 6 views
12

Il y a des questions similaires, mais aucune ne fournit la réponse dont j'ai besoin.Lever des exceptions non gérées dans un thread dans le thread principal?

Si je crée des threads via threading.Thread, qui lancent ensuite des exceptions qui ne sont pas gérées, ces threads sont terminés. Je souhaite conserver l'impression par défaut des détails de l'exception avec la trace de la pile, mais aussi réduire le processus entier.

J'ai considéré qu'il était possible d'intercepter toutes les exceptions dans les threads et de les sur-relancer sur l'objet principal, ou peut-être manuellement de gérer les exceptions par défaut, puis de déclencher un SystemExit fil.

Quelle est la meilleure façon de procéder?

Répondre

15

J'ai écrit à propos de Re-throwing exceptions in Python, y compris quelque chose de très similaire à celui-ci à titre d'exemple.

Sur votre thread de travail que vous faites cela (Python 2.x, voir ci-dessous pour la version Python 3.x):

try: 
    self.result = self.do_something_dangerous() 
except Exception, e: 
    import sys 
    self.exc_info = sys.exc_info() 

et sur votre fil conducteur vous faites ceci:

if self.exc_info: 
    raise self.exc_info[1], None, self.exc_info[2] 
return self.result 

L'exception apparaîtra dans le thread principal comme si elle avait été déclenchée dans le thread de travail.

Python 3.x:

try: 
    self.result = self.do_something_dangerous() 
except Exception as e: 
    import sys 
    self.exc_info = sys.exc_info() 

et sur votre fil conducteur:

if self.exc_info: 
    raise self.exc_info[1].with_traceback(self.exc_info[2]) 
return self.result 
+0

ne voulez-vous pas lancer thrdobj.exc_info dans le thread principal, et pourquoi abandonner le type d'exception lorsque vous le relancez? –

+0

je vois maintenant, a dû lire sur 3arg déclaration raise. mais la question à propos de soi persiste, merci pour une bonne réponse, je vais l'essayer –

+0

Je ne suis pas sûr de savoir quelle est votre question sur soi. Ce code provient d'un objet utilisé pour différer le travail sur un thread de travail, de sorte que le même objet exécute du code dans les threads de travail et principaux. –

9

La seule exception d'un thread secondaire peut augmenter de manière fiable dans le thread principal est KeyboardInterrupt: la façon dont le thread secondaire est-il en appelant la fonction thread.interrupt_main(). Il n'y a aucun moyen d'associer des informations supplémentaires (à propos de la raison de l'exception) avec l'objet d'exception qui est levé - ce dernier est toujours juste un KeyboardInterrupt. Donc, vous devez cacher cette information ailleurs, par ex. sur une instance dédiée de Queue.Queue - cette information peut inclure les résultats que le thread secondaire peut obtenir via sys.exc_info(), et tout ce que vous trouvez utile bien sûr. Le thread principal devra récupérer cette information supplémentaire (et prendre en compte que la file d'attente sera vide si l'interruption du clavier est due à l'utilisateur qui frappe le contrôle C ou similaire, donc, utilisez get_nowait et soyez prêt pour traiter une exception Queue.Empty, par exemple), formatez-la comme vous le souhaitez, et terminez-la (si tous les threads secondaires sont daemon, l'ensemble du processus se termine lorsque le thread principal se termine).

+0

mise à jour de la documentation relative au filetage: https://docs.python.org/3.6/library/_thread.html?highlight=interrupt_main#_thread.interrupt_main – user2682863

Questions connexes