Catch Ctrl+C / SIGINT et de sortie multiprocesses gracieusement en python
Comment puis-je attraper un Ctrl+C dans multi process programme en python et la sortie de tous les processus gracieusement, j'ai besoin de la solution de travailler à la fois sur windows et unix. J'ai essayé ce qui suit:
import multiprocessing
import time
import signal
import sys
jobs = []
def worker():
signal.signal(signal.SIGINT, signal_handler)
while(True):
time.sleep(1.1234)
print "Working..."
def signal_handler(signal, frame):
print 'You pressed Ctrl+C!'
# for p in jobs:
# p.terminate()
sys.exit(0)
if __name__ == "__main__":
for i in range(50):
p = multiprocessing.Process(target=worker)
jobs.append(p)
p.start()
Et c'est le genre de travail, mais je ne pense pas que c'est la bonne solution.
EDIT:
Cela peut être un doublon de cette une
- Double Possible de les Interruptions de Clavier avec python multitraitement de la Piscine
Vous devez vous connecter pour publier un commentaire.
préalablement accepté solution a des conditions de course et il ne fonctionne pas avec
map
etasync
fonctions.La bonne façon de gérer les touches Ctrl+C/
SIGINT
avecmultiprocessing.Pool
est de:SIGINT
avant un processus dePool
est créé. De cette façon, créé processus enfants héritentSIGINT
gestionnaire.SIGINT
gestionnaire dans le processus parent après unePool
a été créé.map_async
etapply_async
au lieu de bloquermap
etapply
.De les mettre ensemble:
Comme @YakovShklarov noté, il y a une fenêtre de temps entre ignorant le signal et unignoring dans le processus parent, au cours de laquelle le signal peut être perdu. À l'aide de
pthread_sigmask
au lieu de bloquer temporairement la livraison du signal dans le processus parent serait d'empêcher que le signal de la perte, cependant, il n'est pas disponible en Python-2.KeyboardInterrupt
etProcess SpawnPoolWorker
de messages et de retraçage de l'multitraitement module et vous devez tuer les processus lancés manuellement. L'on a accepté la réponse ne présentent pas ce comportement.KeyboardInterrupt
?maxtasksperchild
Piscine paramètre. Le nouveau processus créés héritent de la normeSIGINT
gestionnaire de nouveau. Le galets bibliothèque désactiveSIGINT
par défaut pour l'utilisateur dès que le nouveau processus est créé.La solution est basée sur ce lien et ce lien et il a résolu le problème, j'ai déménagé à
Pool
si:fork()
de retour dans le processus de l'enfant etsignal()
appel. Le signal doit être bloqué avant de bifurquer.init_worker
qui est appelé avant laapply_async
- est-ce que vous parlez?get()
les résultats de lamap_async
appel au lieu de cela, l'interruption est retardée jusqu'à ce que le traitement est terminé.Pool
fourches, le nombre d'enfants des processus de l'exécution deinit_worker
premier et une fois par le processus enfant. Cela se produit avant async l'application deworker
fonctions (du piscine mis à disposition) les processus enfants. Cela signifie que le SIG_IGN est appliqué à l'intérieur de chaque processus enfant et il n'est pas nécessaire pour piscine à traiter avec le déblocage du signal car il n'affecte pas le parent (@ChrisKoston). On peut vérifier avecprint(os.getpid())
dans les deux init_worker et travailleur et prenez note de chaque travailleur pid aura eu un init_worker exécuter au préalable dans le processus avec le même pid.Simplement manipuler KeyboardInterrupt-SystemExit des exceptions dans votre processus de travail:
try: time.sleep(60) except BaseException as e: print(e)
et vous verrez si un signal est pris (ime seulement SIGINT). C'est ce que la page de manuel unis aussi.