Ist es möglich, einen laufenden Thread zu beenden, ohne irgendwelche Flags/Semaphoren/etc. zu setzen/zu überprüfen?
Antworten
Zu viele Anzeigen?Es ist durchaus möglich, eine Thread.stop
Methode, wie im folgenden Beispielcode gezeigt:
import sys
import threading
import time
class StopThread(StopIteration):
pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
###############################################################################
def main():
test1 = Thread2(target=printer)
test1.start()
time.sleep(1)
test1.stop()
test1.join()
test2 = Thread2(target=speed_test)
test2.start()
time.sleep(1)
test2.stop()
test2.join()
test3 = Thread3(target=speed_test)
test3.start()
time.sleep(1)
test3.stop()
test3.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
def speed_test(count=0):
try:
while True:
count += 1
except StopThread:
print('Count =', count)
if __name__ == '__main__':
main()
En Thread3
Klasse scheint den Code etwa 33 % schneller auszuführen als die Thread2
Klasse.
Es ist besser, wenn Sie einen Faden nicht abtöten. Eine Möglichkeit wäre, einen "try"-Block in den Thread-Zyklus einzuführen und eine Exception zu werfen, wenn Sie den Thread stoppen wollen (zum Beispiel ein break/return/..., das Ihr for/while/... stoppt). Ich habe dies in meiner App verwendet und es funktioniert...
Ich bin viel zu spät dran, aber ich habe mich mit dem Thema eine ähnliche Frage und die folgende scheint sowohl das Problem perfekt für mich zu lösen UND lässt mich einige grundlegende Thread-Statusprüfung und Bereinigung, wenn der daemonisierte Sub-Thread beendet:
import threading
import time
import atexit
def do_work():
i = 0
@atexit.register
def goodbye():
print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
(i, threading.currentThread().ident))
while True:
print i
i += 1
time.sleep(1)
t = threading.Thread(target=do_work)
t.daemon = True
t.start()
def after_timeout():
print "KILL MAIN THREAD: %s" % threading.currentThread().ident
raise SystemExit
threading.Timer(2, after_timeout).start()
Ausbeute:
0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
Hier ist eine weitere Möglichkeit, dies zu tun, aber mit extrem sauberen und einfachen Code, der in Python 3.7 im Jahr 2021 funktioniert:
import ctypes
def kill_thread(thread):
"""
thread: a threading.Thread object
"""
thread_id = thread.ident
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
Angepasst von hier: https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
Der folgende Workaround kann verwendet werden, um einen Thread zu beenden:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
Dies kann sogar dazu verwendet werden, um Threads, deren Code in einem anderen Modul geschrieben wurde, vom Hauptthread aus zu beenden. Wir können eine globale Variable in diesem Modul deklarieren und sie zum Beenden von Threads verwenden, die in diesem Modul erzeugt wurden.
Ich verwende dies normalerweise, um alle Threads beim Programmende zu beenden. Dies ist vielleicht nicht der perfekte Weg, um Threads zu beenden, könnte aber helfen.