在多线程设计中,我想在程序异常退出时做一些干净的步骤。正在运行的线程应该清理当前任务然后退出,而不是立即被杀死并留下一些脏数据。我发现使用 threading
模块无法捕获 KeyInterrupt
异常(exception)。
这是我的测试代码:
#!/usr/bin/env python3
from time import sleep
def do_sth():
print("I'm doing something...")
sleep(10)
if __name__ == "__main__":
do_sth()
Python 将引发
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
正在运行的线程已经被直接杀死,没有引发异常。
我该如何处理?
最佳答案
一种方法是处理 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 进程例如 - 所有线程都会知道需要关闭。
关于python - 如何让子线程处理Python中的主进程被杀死或关键中断?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30684531/