在多线程设计中,我想在程序异常退出时执行一些干净的步骤。正在运行的线程应该清理当前任务然后退出,而不是立即被杀死并留下一些脏数据。我发现使用threading
模块无法捕获KeyInterrupt
异常。
这是我的测试代码:
#!/usr/bin/env python3
from time import sleep
def do_sth():
print("I'm doing something...")
sleep(10)
if __name__ == "__main__":
do_sth()
当我按KeyInterrupt
CTRL-c
异常
$ Python3 test.py
I'm doing something ...
^C
Traceback (most recent call last):
File "test.py", line 10, in <module>
do_sth ()
File "test.py", line 7, in do_sth
sleep (10)
KeyboardInterrupt
所以我可以抓住这个例外。
def do_sth ():
try:
print ("I'm doing something ...")
sleep (10)
except (KeyboardInterrupt, SystemExit):
print ("I'm doing some clean steps and exit.")
但是当我使用线程模块时,根本不会引发此异常。
#!/usr/bin/env python3
from time import sleep
import threading
def do_sth():
print("I'm doing something...")
sleep(10)
if __name__ == '__main__':
t = threading.Thread(target=do_sth)
t.start()
t.join()
结果:
$ python3 test.py
I'm doing something...
^C
正在运行的线程被直接杀死,并且没有异常被引发。
我该如何处理?
答案 0 :(得分:0)
一种方法是处理KeyboardInterrupt异常。
在这种情况下要做的另一件事是跨所有线程管理应用程序的状态。 其中一个解决方案是在代码中添加对Signals的支持。它可以优雅地处理关闭过程。
以下是一个简单的设置:
class SignalHandler:
continue_running = True
def __init__(self):
signal.signal(signal.SIGUSR2, self.signal_handler)
signal.signal(signal.SIGTERM, self.signal_handler)
signal.signal(signal.SIGINT, self.signal_handler)
logging.info("SignalHandler::Init")
def signal_handler(self, num, stack):
logging.warning('Received signal %d in %s' % (num, threading.currentThread()))
SignalHandler.continue_running = False
logging.warning("Time to SHUT DOWN ALL MODULES")
所有主题都会尝试利用SignalHandler.continue_running
中的状态来确保他们都知道何时停止。
如果有人试图通过调用kill -2 [PID]
来杀死这个python进程 - 所有线程都会知道需要关闭。