Hoe sluit ik de hele applicatie uit een Python-thread?

Hoe kan ik mijn hele Python-toepassing afsluiten vanuit een van de threads? sys.exit()beëindigt alleen de thread waarin deze wordt aangeroepen, dus dat helpt niet.

Ik zou geen os.kill()-oplossing willen gebruiken, omdat deze niet erg schoon is.


Antwoord 1, autoriteit 100%

Kort antwoord: gebruik os._exit.

Lang antwoord met voorbeeld:

Ik heb een eenvoudig threading-voorbeeld uit een tutorial over 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()

Als je sys.exit(1)als commentaar laat staan, zal het script sterven nadat de derde thread is afgedrukt. Als u sys.exit(1)gebruikt en commentaar geeft op os._exit(1), drukt de derde thread niet(done), en het programma doorloopt alle zeven threads.

os._exit“moet normaal gesproken alleen worden gebruikt in het onderliggende proces na een fork()” — en een aparte thread komt daar dicht genoeg bij voor jouw doel. Merk ook op dat er verschillende opgesomde waarden direct na os._exitin die handleiding staan, en dat je die als argumenten zou moeten verkiezen boven os._exitin plaats van eenvoudige getallen zoals I gebruikt in het bovenstaande voorbeeld.


Antwoord 2, autoriteit 74%

Als al je threads behalve de belangrijkste daemons zijn, is de beste aanpak over het algemeen thread.interrupt_main()— elke thread kan het gebruiken om een ​​KeyboardInterruptin de hoofdthread te plaatsen, wat normaal gesproken kan leiden tot een redelijk schone exit van de hoofdthread (inclusief finalizers in de hoofdthread wordt gebeld, enz.).

Natuurlijk, als dit resulteert in een niet-daemon-thread die het hele proces levend houdt, moet je opvolgen met os._exitzoals Mark aanbeveelt — maar ik zie dat als de laatste resort (een beetje zoals een kill -9😉 omdat het de dingen behoorlijk bruusk beëindigt (finalizers worden niet uitgevoerd, inclusief try/finally-blokken, withblokken, atexit-functies, enz.).


Antwoord 3, autoriteit 26%

Het gebruik van thread.interrupt_main()kan in sommige situaties niet helpen. KeyboardInterrupts worden vaak gebruikt in opdrachtregeltoepassingen om de huidige opdracht af te sluiten of om de invoerregel op te schonen.

Bovendien zal os._exithet proces onmiddellijk beëindigen zonder dat er finallyblokken in uw code worden uitgevoerd, wat gevaarlijk kan zijn (bestanden en verbindingen worden niet gesloten voor voorbeeld).

De oplossing die ik heb gevonden is het registreren van een signaalhandler in de hoofdthread die een aangepaste uitzondering genereert. Gebruik de achtergronddraad om het signaal af te vuren.

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')

Verwante vragen:


Antwoord 4, autoriteit 6%

De gemakkelijkste manier om het hele programma af te sluiten, is door het programma te beëindigen met de proces-id (pid).

import os
import psutil
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()

Om psutl te installeren:- “pip install psutil”

Other episodes