Ist es möglich, einen laufenden Thread zu beenden, ohne irgendwelche Flags/Semaphoren/etc. zu setzen/zu überprüfen?
Antworten
Zu viele Anzeigen?In Python können Sie einen Thread nicht direkt beenden.
Wenn Sie NICHT wirklich einen Thread (!) benötigen, können Sie statt der Verwendung des Einfädeln Paket ist die Verwendung der Multiprozessorbetrieb Paket . Um einen Prozess zu beenden, können Sie hier einfach die Methode aufrufen:
yourProcess.terminate() # kill the process!
Python wird Ihren Prozess beenden (unter Unix durch das SIGTERM-Signal, unter Windows durch die TerminateProcess()
Aufruf). Achten Sie darauf, es zu benutzen, wenn Sie eine Warteschlange oder eine Pipe verwenden! (es kann die Daten in der Queue/Pipe beschädigen)
Beachten Sie, dass die multiprocessing.Event
und die multiprocessing.Semaphore
funktionieren genau so wie die threading.Event
und die threading.Semaphore
beziehungsweise. Die ersteren sind in der Tat Klone der letzteren.
Wenn Sie einen Thread WIRKLICH brauchen, gibt es keine Möglichkeit, ihn direkt zu töten. Was Sie jedoch tun können, ist die Verwendung eines "Daemon-Thread" . In Python kann ein Thread sogar als Daemon :
yourThread.daemon = True # set the Thread as a "daemon thread"
Das Hauptprogramm wird beendet, wenn keine lebenden Nicht-Daemon-Threads mehr vorhanden sind. Mit anderen Worten, wenn Ihr Haupt-Thread (der natürlich ein Nicht-Daemon-Thread ist) seine Operationen beendet, wird das Programm beendet, auch wenn noch einige Daemon-Threads in Betrieb sind.
Beachten Sie, dass es notwendig ist, einen Thread als daemon
vor der start()
Methode aufgerufen wird!
Natürlich können und sollten Sie die daemon
auch bei multiprocessing
. Wenn der Hauptprozess beendet wird, versucht er, alle seine dämonischen Kindprozesse zu beenden.
Abschließend möchten wir Sie darauf hinweisen, dass sys.exit()
y os.kill()
sind keine Wahlmöglichkeiten.
Dies basiert auf dem thread2 -- abschaltbare Threads ActiveState-Rezept.
Sie müssen anrufen PyThreadState_SetAsyncExc()
die nur über die Website ctypes
Modul.
Dies wurde nur mit Python 2.7.3 getestet, aber es ist wahrscheinlich, dass es auch mit anderen aktuellen 2.x-Versionen funktioniert. PyThreadState_SetAsyncExc()
ist in Python 3 aus Gründen der Abwärtskompatibilität noch vorhanden (ich habe es aber nicht getestet).
import ctypes
def terminate_thread(thread):
"""Terminates a python thread from another thread.
:param thread: a threading.Thread instance
"""
if not thread.isAlive():
return
exc = ctypes.py_object(SystemExit)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
ctypes.c_long(thread.ident), exc)
if res == 0:
raise ValueError("nonexistent thread id")
elif res > 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread.ident, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
Sie sollten niemals ein Thema gewaltsam beenden, ohne mit ihm zu kooperieren.
Durch das Beenden eines Threads werden alle Garantien für Try-/Final-Blöcke aufgehoben, so dass Sie möglicherweise Sperren, Dateien usw. offen lassen.
Das einzige Mal, dass man argumentieren kann, dass das gewaltsame Beenden von Threads eine gute Idee ist, ist, wenn man ein Programm schnell beenden will, aber niemals einzelne Threads.
Wenn Sie explizit aufrufen time.sleep()
als Teil Ihres Threads (z.B. Abfrage eines externen Dienstes), ist eine Verbesserung der Methode von Phillipe die Verwendung des Timeouts in der event
's wait()
Methode, wo immer Sie sleep()
Zum Beispiel:
import threading
class KillableThread(threading.Thread):
def __init__(self, sleep_interval=1):
super().__init__()
self._kill = threading.Event()
self._interval = sleep_interval
def run(self):
while True:
print("Do Something")
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
Um es dann auszuführen
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
Der Vorteil der Verwendung von wait()
代わりに sleep()
Der Vorteil der regelmäßigen Überprüfung des Ereignisses besteht darin, dass man längere Schlafintervalle einprogrammieren kann und der Thread fast sofort gestoppt wird (wenn man sonst sleep()
ing) und meiner Meinung nach ist der Code für die Behandlung des Ausstiegs wesentlich einfacher.