1000 Stimmen

Gibt es eine Möglichkeit, einen Thread zu löschen?

Ist es möglich, einen laufenden Thread zu beenden, ohne irgendwelche Flags/Semaphoren/etc. zu setzen/zu überprüfen?

13voto

Noctis Skytower Punkte 20111

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.

12voto

Giancarlo Punkte 4381

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...

10voto

slumtrimpet Punkte 2857

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]

8voto

serg06 Punkte 1134

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/

8voto

Amit Chahar Punkte 2399

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X