Comment puis-je quitter l'intégralité de mon application Python à partir de l'un de ses threads? Sys.exit () ne termine que le thread dans lequel elle est appelée, donc cela ne sert à rien.
Je ne voudrais pas utiliser une solution os.kill (), car ce n'est pas très propre.
Si tous vos threads sauf les principaux sont des démons, la meilleure approche est généralement thread.interrupt_main () - n'importe quel thread peut l'utiliser pour augmenter un KeyboardInterrupt
dans le thread principal, ce qui peut normalement conduire à une sortie raisonnablement propre du thread principal (y compris les finaliseurs du thread principal appelés, etc.).
Bien sûr, si cela se traduit par un thread non démon qui maintient l'ensemble du processus en vie, vous devez effectuer un suivi avec os._exit
comme le recommande Mark - mais je verrais cela en dernier recours (un peu comme un kill -9
;-) car il termine les choses assez brusquement (les finaliseurs ne sont pas exécutés, y compris try/finally
blocs, with
blocs, atexit
fonctions, etc.).
Réponse courte: utilisez os._exit
.
Réponse longue avec exemple:
J'ai tiré et légèrement modifié un exemple de filetage simple de n tutoriel sur DevShed :
import threading, sys, os
theVar = 1
class MyThread ( threading.Thread ):
def run ( self ):
global theVar
print 'This is thread ' + str ( theVar ) + ' speaking.'
print 'Hello and good bye.'
theVar = theVar + 1
if theVar == 4:
#sys.exit(1)
os._exit(1)
print '(done)'
for x in xrange ( 7 ):
MyThread().start()
Si vous gardez sys.exit(1)
mis en commentaire, le script mourra après l'impression du troisième thread. Si vous utilisez sys.exit(1)
et commentez os._exit(1)
, le troisième thread n'imprime pas (done)
et le programme parcourt les sept threads.
os._exit
"Ne devrait normalement être utilisé dans le processus enfant qu'après un fork ()" - et un thread séparé est suffisamment proche de celui pour votre usage. Notez également qu'il existe plusieurs valeurs énumérées juste après os._exit
Dans cette page de manuel, et vous devriez préférer celles-ci comme arguments à os._exit
Au lieu de simples chiffres comme je l'ai utilisé dans l'exemple ci-dessus.
L'utilisation de thread.interrupt_main()
peut ne pas aider dans certaines situations. KeyboardInterrupt
s sont souvent utilisés dans les applications de ligne de commande pour quitter la commande en cours ou pour nettoyer la ligne d'entrée.
En plus, os._exit
va tuer le processus immédiatement sans exécuter de bloc finally
dans votre code, ce qui peut être dangereux (les fichiers et les connexions ne seront pas fermés par exemple).
La solution que j'ai trouvée consiste à enregistrer un gestionnaire de signal dans le thread principal qui déclenche une exception personnalisée. Utilisez le fil d'arrière-plan pour déclencher le signal.
import signal
import os
import threading
import time
class ExitCommand(Exception):
pass
def signal_handler(signal, frame):
raise ExitCommand()
def thread_job():
time.sleep(5)
os.kill(os.getpid(), signal.SIGUSR1)
signal.signal(signal.SIGUSR1, signal_handler)
threading.Thread(target=thread_job).start() # thread will fire in 5 seconds
try:
while True:
user_input = raw_input('Blocked by raw_input loop ')
# do something with 'user_input'
except ExitCommand:
pass
finally:
print('finally will still run')
Questions connexes: