Python: 为什么来自线程的`sys.exit(msg)`不将`msg`打印到stderr?
今天我发现一个问题,就是从子线程调用 sys.exit()
并不会结束主进程。我之前并不知道这一点,这没关系,但我花了很长时间才意识到这一点。如果 sys.exit(msg)
能把 msg
打印到 stderr
,那就能节省很多很多时间。可惜它并没有这样做。
结果发现,这并不是我应用程序里的真正错误;它是故意调用 sys.exit(msg)
并传入了一个有意义的错误信息——但我就是没能看到这一点。
在 sys.exit()
的文档中提到:
"[...] 任何其他对象都会被打印到 sys.stderr
,并导致退出代码为 1"
但这对于从子线程调用来说并不成立,因为 sys.exit()
显然表现得像是 thread.exit()
:
"引发 SystemExit 异常。当没有被捕获时,这将导致线程静默退出"
我认为,当程序员希望 sys.exit(msg)
打印错误信息时,这个信息应该被打印出来——无论是从哪里调用的。为什么不呢?我目前看不出有什么理由。至少在 sys.exit()
的文档中应该有个提示,说明在线程中不会打印消息。
你觉得怎么样?为什么错误信息在线程中被隐藏?这样做有意义吗?
最好的祝福,
Jan-Philip Gehrcke
2 个回答
在Python中,并不是所有的线程都是一样的。当你在一个线程中调用sys.exit时,其实并不会让整个程序退出。所以,如果你在一个子线程中调用sys.exit(),这就没有什么意义了,因此它的表现可能和你想的不一样。
这 页面 详细讲解了线程对象,以及线程和特殊的“主”线程之间的区别。
我同意,Python的文档在关于sys.exit和SystemExit的部分是不准确的,或者更确切地说是不完整的,特别是当这些函数在主线程以外的线程中被调用或抛出时。请在Python的在线跟踪系统上提交一个文档问题,这样可以在未来的文档更新中解决这个问题(可能很快就会更新,因为修正文档比修复代码要简单得多;-)。
解决这个问题其实很简单——只需要用一个装饰器把你作为threading.Thread
目标的函数包裹起来,装饰器里用try
/except SystemExit, e:
来处理,然后在程序结束前执行你需要的“写入错误输出”的额外功能(或者,可能更好的是,使用logging.error来替代)。不过,正如你所指出的文档问题,除非你真的遇到这个问题并花时间调试,否则很难想到要这样做,就像你所经历的那样(这也是为核心Python开发者们共同承担的责任——抱歉!)。