Python - 取消计时器线程
我正在尝试创建一个方法,让它在我的主脚本后台定时运行:
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 个回答
试着重新抛出 KeyboardInterrupt
异常:http://effbot.org/zone/stupid-exceptions-keyboardinterrupt.htm
不过,这可能还是不管用;你很可能遇到了这个问题:
线程和中断的互动很奇怪:
KeyboardInterrupt
异常会被随机的线程接收到。(当信号模块可用时,中断总是会发送到主线程。)
简单来说,你不能确定 KeyboardInterrupt
会发送到你的主线程。为了解决这个问题,你可以看看signal
模块。
编辑:一种更优雅的取消线程的方法是使用一个共享变量,线程会查看这个变量,如果它变成 false
,线程就会退出。然后,如果你想从主线程中结束这个线程,你只需把这个变量设置为 false
。
你只需要把 Timer
线程设置为 daemon
线程。
def hello_world(self):
print 'Hello!'
t = threading.Timer(2,hello_world)
t.daemon = True
t.start()
这样的话,当主线程结束时,比如因为按下了 KeyboardInterrupt
,它就会自动退出。
设置为 daemon
后,当程序里只剩下 daemon
线程时,整个程序就会退出。
为了更详细地解释一下Aphex的回答,主线程几乎不可能捕捉到键盘中断信号,除非你的手指非常快。主线程几乎是立刻就退出了!你可以试试这个:
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秒后会自动退出——如果你愿意,可以把这个数字设得更大。你也可以使用忙循环来重复调用睡眠,但我觉得这样做没有必要。