42

我在这里尝试做的是使用键盘中断来退出程序中所有正在进行的线程。这是创建线程的代码的精简版本:

for i in taskDictionary:
    try:
        sleep(60)
        thread = Thread(target = mainModule.executeThread)
        thread.start()
    except KeyboardInterrupt:
        thread.__stop()

程序本身要复杂得多,考虑到影响线程的大量不同变量,甚至可以选择以顺序模式启动,其中任务不是线程化的,而是一个接一个地启动,因此可能会出现一些问题有了这个小小的变化,我就想到了。我以产生 50/50 结果的方式做到了这一点。中断会起作用,但线程永远不会干净地退出。有时它们会继续运行,但会停止未来线程的执行,有时它们会因中断而出现大量错误而退出,有时中断什么也不做。上次我运行这个程序时,程序停止了任何未来线程的执行,但没有停止当前线程。有没有办法退出线程而不进入线程实际执行的模块?

4

2 回答 2

69

一个类似的问题是“你如何杀死一个线程?”

您在线程中创建一个退出处理程序,该处理程序由线程模块中的锁或事件对象控制。然后,您只需移除锁或向事件对象发出信号。这会通知线程它应该停止处理并正常退出。在主程序中向线程发出信号后,唯一要做的就是使用等待线程关闭的thread.join()方法。main

一个简短的例子:

import threading
import time

def timed_output(name, delay, run_event):
    while run_event.is_set():
        time.sleep(delay)
        print name,": New Message!"


def main():
    run_event = threading.Event()
    run_event.set()
    d1 = 1
    t1 = threading.Thread(target = timed_output, args = ("bob",d1,run_event))

    d2 = 2
    t2 = threading.Thread(target = timed_output, args = ("paul",d2,run_event))

    t1.start()
    time.sleep(.5)
    t2.start()

    try:
        while 1:
            time.sleep(.1)
    except KeyboardInterrupt:
        print "attempting to close threads. Max wait =",max(d1,d2)
        run_event.clear()
        t1.join()
        t2.join()
        print "threads successfully closed"

if __name__ == '__main__':
    main()

如果您真的需要杀死线程的功能,请使用多处理。它允许您将 SIGTERM 发送到各个“进程”(它也非常类似于线程模块)。一般来说,线程适用于受 IO 限制的情况,而多处理适用于真正受处理器限制的情况。

于 2012-07-11T15:54:45.840 回答
3

有几个选项不需要在线程之间使用锁或其他信号。一种是将线程设置为daemons,当主线程退出时将自动终止。另一种是使用进程,如果需要终止它们并保持主程序运行,则可以从主进程调用终止方法。

如果您有线程阻塞输入,这两种方法都特别有用。虽然在大多数情况下使用超时和定期检查信号不会产生太多开销,但使用守护进程或进程消除了对任何繁忙循环或显着增加的复杂性的需求。

有关这些解决方案的更多详细信息以及关于杀死线程问题的讨论,请参阅此问题的答案。

于 2018-12-23T20:59:14.017 回答