在主线程中引发线程的未处理异常?
有一些类似的问题,但没有一个能给我想要的答案。
如果我通过 threading.Thread
创建线程,然后这些线程抛出未处理的异常,这些线程就会被终止。我希望保留异常详细信息和调用栈的默认打印输出,但同时也想让整个程序停止运行。
我考虑过可能可以在线程中捕获所有异常,然后在主线程中重新抛出这些异常,或者也许可以手动执行默认的异常处理,然后在主线程中抛出一个 SystemExit
。
那么,最好的方法是什么呢?
3 个回答
很不幸,大家认可的答案并没有解决问题。你其实应该把异常的详细信息放进一个队列里。请看看这个链接:在Python中捕获线程的异常到调用线程
在一个程序中,只有一个特殊的情况可以让一个副线程在主线程中安全地引发异常,那就是 KeyboardInterrupt
。副线程实现这个的方式是通过调用一个函数 thread.interrupt_main()
。不过,值得注意的是,抛出的异常对象总是简单的 KeyboardInterrupt
,你不能在这个异常上附加额外的信息,比如为什么会出现这个异常。因此,你需要把这些信息存放在其他地方,比如一个专门的 队列 实例中。这些信息可以包括副线程通过 sys.exc_info()
获取的结果,以及你认为有用的其他信息。
主线程需要从这个队列中取回额外的信息(并且要考虑到,如果键盘中断是因为用户按了控制键C等,队列可能会是空的,所以要使用 get_nowait
方法,并准备处理 Queue.Empty
异常)。然后,你可以根据需要格式化这些信息,并结束程序(如果所有的副线程都是 守护线程,那么当主线程结束时,整个程序也会结束)。
我写了一篇关于在Python中重新抛出异常的文章,里面有类似的例子。
在你的工作线程中,你可以这样做(Python 3.x,下面会有Python 2.x的版本):
try:
self.result = self.do_something_dangerous()
except Exception as e:
import sys
self.exc_info = sys.exc_info()
然后在你的主线程中:
if self.exc_info:
raise self.exc_info[1].with_traceback(self.exc_info[2])
return self.result
Python 2.x:
try:
self.result = self.do_something_dangerous()
except Exception, e:
import sys
self.exc_info = sys.exc_info()
在你的主线程中,你可以这样做:
if self.exc_info:
raise self.exc_info[1], None, self.exc_info[2]
return self.result
这样,异常会在主线程中出现,就好像它是在工作线程中抛出的。