Pourquoi ne sys.exit () ne quitte pas lorsqu'il est appelé à l'intérieur d'un fil en Python?

StackOverflow https://stackoverflow.com/questions/905189

  •  05-09-2019
  •  | 
  •  

Question

Cela pourrait être une question stupide, mais je tester certaines de mes hypothèses sur Python et je suis confus quant à la raison pour laquelle l'extrait de code suivant ne quitte pas lorsqu'il est appelé dans le fil, mais se retirerait lorsqu'il est appelé dans la thread principal.

import sys, time
from threading import Thread

def testexit():
    time.sleep(5)
    sys.exit()
    print "post thread exit"

t = Thread(target = testexit)
t.start()
t.join()
print "pre main exit, post thread exit"
sys.exit()
print "post main exit"

Les documents de l'état sys.exit () que l'appel doit sortir du python. Je peux voir de la sortie de ce programme qui est jamais imprimé « sortie post-fil », mais le thread principal ne cesse de passer même après que le fil de sortie appelle.

est une instance distincte de l'interprète en cours de création pour chaque thread, et l'appel à quitter () est juste de quitter cette instance séparée? Si oui, comment l'implémentation des threads ne gère l'accès aux ressources partagées? Que faire si je voulais quitter le programme à partir du fil (pas que je veux vraiment, mais juste pour que je comprends)?

Était-ce utile?

La solution

sys.exit () soulève l'exception SystemExit, comme le fait Thread.exit (). Donc, quand sys.exit () soulève cette exception dans ce fil, il a le même effet que l'appel Thread.exit (), ce qui explique pourquoi seules les sorties de fil.

Autres conseils

  

Et si je voulais quitter le programme   du fil?

En dehors de la méthode décrite Deestan vous pouvez appeler os._exit (notez le trait de soulignement). Avant de l'utiliser assurez-vous que vous comprenez qu'il fait pas (comme opérations de nettoyage appelant __del__ ou similaire).

  

Et si je voulais quitter le programme à partir du fil (pas que je   en fait envie, mais juste pour que je comprends)?

Au moins sur Linux, vous pouvez faire quelque chose comme:

os.kill(os.getpid(), signal.SIGINT)

envoyer un SIGINT au thread principal où il peut être traité comme un KeyboardInterrupt.

BTW: Sous Windows, vous ne pouvez envoyer un signal SIGTERM, qui ne peut être pris à partir de Python. (Là, je préférerais appeler os._exit comme suggéré par Helmut)

Est-ce le fait que « avant la sortie principale, sortie post-fil » est imprimé ce qui vous tracasse?

Contrairement à d'autres langues (comme Java) où l'analogique sys.exit (System.exit, dans le cas de Java) provoque la machine virtuelle / processus / interprète d'arrêter immédiatement, le sys.exit Python lancers francs seulement une exception:. Une exception SystemExit en particulier

Voici les documents pour sys.exit (juste print sys.exit.__doc__):

  

Sortir de l'interprète en augmentant SystemExit (statut).
  Si l'état est omis ou pas, il par défaut à zéro (à savoir, le succès).
  Si l'état est numérique, il sera utilisé comme l'état de sortie du système.
  S'il est un autre type d'objet, il sera imprimé et le système
  état de sortie sera l'un (à savoir, l'échec).

Cela a quelques conséquences:

  • dans un fil, il tue tout le fil en cours, et non l'ensemble du processus (en supposant qu'il obtient tout le chemin vers le sommet de la pile ...)
  • Destructeurs d'objet (__del__) sont potentiellement invoqués comme les cadres de pile qui font référence à ces objets sont dénouées
  • enfin blocs sont exécutés comme les déroulements de la pile
  • vous pouvez attraper une exception SystemExit

Le dernier est peut-être le plus surprenant, et est encore une autre raison pour laquelle vous devriez avoir presque jamais une déclaration sans réserve de except dans votre code Python.

  

Et si je voulais quitter le programme   du fil (pas que je fait   veux, mais juste pour que je comprends)?

Ma méthode préférée est un message Erlang-ish qui passe. Légèrement simlified, je le fais comme ceci:

import sys, time
import threading
import Queue # thread-safe

class CleanExit:
  pass

ipq = Queue.Queue()

def testexit(ipq):
  time.sleep(5)
  ipq.put(CleanExit)
  return

threading.Thread(target=testexit, args=(ipq,)).start()
while True:
  print "Working..."
  time.sleep(1)
  try:
    if ipq.get_nowait() == CleanExit:
      sys.exit()
  except Queue.Empty:
    pass
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top