Python - 取消定时器线程

5
我正在尝试创建一个定时器方法,可以在我的主要脚本后台运行:
def hello_world(self):
        print 'Hello!'
        threading.Timer(2,hello_world).start()

if __name__ == "__main__":
    try:
        hello_world()
    except KeyboardInterrupt:
        print '\nGoodbye!'

当我试图使用键盘中断脚本时,会收到以下消息:

Exception KeyboardInterrupt in <module 'threading' from '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/threading.py'> ignored

如何关闭线程以便干净退出应用程序?
3个回答

12

稍微解释一下Aphex的答案,除非你的手速非常快,否则主线程不可能捕获到KeyboardInterrupt信号。主线程几乎立即退出!试试这个:

import threading

def hello_world():
        print 'Hello!'
        threading.Timer(2,hello_world).start()

if __name__ == "__main__":
    try:
        hello_world()
    except KeyboardInterrupt:
        print '\nGoodbye!'
    print "main thread exited"
更一般地说,我不建议像这样使用自调用计时器,因为它会创建许多线程。只需创建一个线程并在其中调用time.sleep即可。 然而,只要保持主线程运行,似乎可以在其中捕获KeyboardInterrupt异常。关键是将该线程设置为daemon线程,以便在主线程退出时退出。
import threading
import time

def hello_world():
    while(True):
        print 'Hello!'
        time.sleep(2)

if __name__ == "__main__":
    hw_thread = threading.Thread(target = hello_world)
    hw_thread.daemon = True
    hw_thread.start()
    try:
        time.sleep(1000)
    except KeyboardInterrupt:
        print '\nGoodbye!'

这将在1000秒后自动退出 -- 如果您喜欢,您可以将该数字增加到更大。您也可以使用一个忙循环来重复 sleep 调用,但我真的看不出有什么意义。


11
你只需要将 Timer 线程设置为守护线程即可。
def hello_world(self):
    print 'Hello!'
    t = threading.Timer(2,hello_world)
    t.daemon = True
    t.start()

如果设置为daemon线程,当主线程退出时,如因KeyboardInterrupt中断,则导致程序退出。

daemon设置会在仅剩daemon线程时,导致整个程序退出。


1
太好了!这是正确的答案。 这是避免Ctrl+C干扰退出的Timer线程的唯一方法。最终,所有计时器都应该被打开...因为即使你只有一个计时器...也不太可能希望Ctrl+C杀死其中任何一个计时器...而不关闭主线程。 - Erik Aronesty

2
尝试重新引发KeyboardInterrupt异常:http://effbot.org/zone/stupid-exceptions-keyboardinterrupt.htm 不过这仍然可能无法奏效;很有可能你遇到了这个警告

线程与中断的交互行为很奇怪:KeyboardInterrupt异常会被任意一个线程接收。当signal模块可用时,中断始终会传递给主线程。

简而言之,你不能确定KeyboardInterrupt是否会传递给主线程。要解决此问题,您可以考虑使用signal模块。 编辑:一种更优雅的取消线程的方法是设置一个共享变量,线程查看该变量并在其变为false时退出。然后,如果您想从主线程结束线程,只需将变量设置为false即可。

2
关于您的编辑:这不是共享变量。请使用threading.Event来解决。 - Eli Bendersky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接