是否有可能终止一个正在运行的线程而不设置/检查任何标志/信号/等等?


当前回答

这里还有另一种方法,但代码非常干净和简单,适用于2021年的Python 3.7:

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

改编自:https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/

其他回答

你不应该在没有与线程合作的情况下强行终止线程。

杀死一个线程消除了try/finally阻塞设置的任何保证,所以你可能会让锁锁定,文件打开等等。

唯一可以认为强制终止线程是一个好主意的情况是快速终止程序,但绝不是单个线程。

没有官方API来做这个,没有。

你需要使用平台API来杀死线程,例如pthread_kill或TerminateThread。你可以访问这样的API,例如通过pythonwin,或通过ctypes。

注意,这本质上是不安全的。这可能会导致不可收集的垃圾(来自堆栈帧的局部变量,成为垃圾),并可能导致死锁,如果被杀死的线程在被杀死时具有GIL。

实现一个线程是绝对可能的。方法,如下例代码所示:

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

Thread3类运行代码的速度似乎比Thread2类快大约33%。

有一个图书馆就是为了这个目的而建的,别说了。尽管这里列出的一些注意事项仍然适用,但至少这个库提供了一种常规的、可重复的技术来实现既定的目标。

如果您确实需要终止子任务的能力,请使用另一种实现。Multiprocessing和gevent都支持不加选择地杀死一个“线程”。

Python的线程不支持取消。不要尝试。你的代码很可能死锁、损坏或泄漏内存,或者有其他意想不到的“有趣的”难以调试的效果,这种情况很少发生,而且不确定。