在主线程中引发线程的未处理异常?

16 投票
3 回答
25636 浏览
提问于 2025-04-15 16:43

有一些类似的问题,但没有一个能给我想要的答案。

如果我通过 threading.Thread 创建线程,然后这些线程抛出未处理的异常,这些线程就会被终止。我希望保留异常详细信息和调用栈的默认打印输出,但同时也想让整个程序停止运行。

我考虑过可能可以在线程中捕获所有异常,然后在主线程中重新抛出这些异常,或者也许可以手动执行默认的异常处理,然后在主线程中抛出一个 SystemExit

那么,最好的方法是什么呢?

3 个回答

5

很不幸,大家认可的答案并没有解决问题。你其实应该把异常的详细信息放进一个队列里。请看看这个链接:在Python中捕获线程的异常到调用线程

14

在一个程序中,只有一个特殊的情况可以让一个副线程在主线程中安全地引发异常,那就是 KeyboardInterrupt。副线程实现这个的方式是通过调用一个函数 thread.interrupt_main()。不过,值得注意的是,抛出的异常对象总是简单的 KeyboardInterrupt,你不能在这个异常上附加额外的信息,比如为什么会出现这个异常。因此,你需要把这些信息存放在其他地方,比如一个专门的 队列 实例中。这些信息可以包括副线程通过 sys.exc_info() 获取的结果,以及你认为有用的其他信息。

主线程需要从这个队列中取回额外的信息(并且要考虑到,如果键盘中断是因为用户按了控制键C等,队列可能会是空的,所以要使用 get_nowait 方法,并准备处理 Queue.Empty 异常)。然后,你可以根据需要格式化这些信息,并结束程序(如果所有的副线程都是 守护线程,那么当主线程结束时,整个程序也会结束)。

20

我写了一篇关于在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

这样,异常会在主线程中出现,就好像它是在工作线程中抛出的。

撰写回答