我有一个python3程序,它启动了第二个线程(除了主线程之外)来异步处理一些事件。理想情况下,我的程序可以完美地运行,并且永远不会有未处理的异常。但是事情发生了。当/如果有异常时,我希望整个解释器退出错误代码,就像它是一个单独的线程一样。这可能吗?
现在,如果在派生线程上发生异常,它会打印出通常的错误信息,但不会退出,主线程会继续运行。
示例
import threading
import time
def countdown(initial):
while True:
print(initial[0])
initial = initial[1:]
time.sleep(1)
if __name__ == '__main__':
helper = threading.Thread(target=countdown, args=['failsoon'])
helper.start()
time.sleep(0.5)
#countdown('THISWILLTAKELONGERTOFAILBECAUSEITSMOREDATA')
countdown('FAST')
countdown
最终将无法从字符串中访问[0]
,因为它已被清空,导致IndexError: string index out of range
错误。目标是无论main还是helper首先死亡,整个程序都会死亡,但堆栈跟踪信息仍然输出。
尝试的解决方案
经过一番挖掘,我的想法是使用sys.excepthook
。我添加了以下内容:
def killAll(etype, value, tb):
print('KILL ALL')
traceback.print_exception(etype, value, tb)
os.kill(os.getpid(), signal.SIGKILL)
sys.excepthook = killAll
如果主线程是第一个死的线程,这是可行的。但在另一种情况下,它不是。这似乎是一个已知的问题(https://bugs.python.org/issue1230540)。我将尝试一些变通办法。
虽然这个例子显示了我创建的一个主线程和一个辅助线程,但我对运行其他人的库来启动线程的一般情况感兴趣。
4条答案
按热度按时间vlju58qv1#
你可以简单地在你的线程中抛出一个错误,让主线程处理并报告这个错误,然后你甚至可以终止程序。
例如,在您的工作线程上:
在主线程上:
所以为了给予你一个更完整的画面,你的代码可能看起来像这样:
(我额外添加了一行代码来记录是哪个线程导致了错误,以防你有多个线程,给它们命名也是一个很好的习惯)
mtb9vblg2#
我的解决方案最终是solution posted here和上面的
SIGKILL
解决方案的完美结合。我将以下killall.py
子模块添加到我的包中:然后在启动任何其他线程(我自己创建的或从其他导入的库)之前立即运行
install
。m2xkgtsf3#
我只是想分享我的简单解决方案。
在我的例子中,我希望异常正常显示,但随后立即停止程序。我能够通过启动一个定时器线程来实现这一点,在引发异常之前有一个小的延迟来调用
os._exit
。fcy6dtqo4#
Python 3.8添加了threading.excepthook,这使得可以更干净地处理它。
我写了一个包“unhandled_exit”来完成这个任务。它基本上是在默认处理程序之后添加
os._exit(1)
。这意味着在进程退出之前可以获得正常的回溯。软件包在这里发布到pypi:https://pypi.org/project/unhandled_exit/
代码在这里:https://github.com/rfjakob/unhandled_exit/blob/master/unhandled_exit/__init__.py
用法很简单: