【问题标题】:Printing Daemonic Thread Exceptions in Python在 Python 中打印守护线程异常
【发布时间】:2009-05-17 20:45:28
【问题描述】:

Python 不会打印来自守护线程中引发的异常的回溯消息。

例如,此代码创建一个守护线程并在新线程中引发异常:

def error_raiser():
    raise Exception

import threading
thread = threading.Thread(target=error_raiser)
thread.daemon = True
thread.start()

但不打印回溯。 (它没有输出)。

但是,如果线程未设置为守护线程,Python 将打印回溯。这是相同的代码,但注释掉了一行:

def error_raiser():
    raise Exception

import threading
thread = threading.Thread(target=error_raiser)
# thread.daemon = True
thread.start()

和输出:

Exception in Thread-1:
Traceback (most recent call last):
  File "C:\Python26\lib\threading.py", line 525, in __bootstrap_inner
    self.run()
  File "C:\Python26\lib\threading.py", line 477, in run
    self.__target(*self.__args, **self.__kwargs)
  File "test.py", line 2, in error_raiser
    raise Exception
Exception

在 Python 2.6.2 和 Python 3.0.1 中执行此代码并给出相同的结果。然而,有趣的是,如果我通过在 IPython shell 中导入代码来执行代码,无论线程是否为守护线程,都会显示异常。

根据文档,'daemon' 标志的唯一意义是“当只剩下守护线程时,整个 Python 程序退出。”这会让我相信,在异常之后不打印回溯是 Python 中的一个错误,除非我错过了文档中的某些内容。

这是一个错误,还是我错过了文档中的某些内容而这种行为是故意的?如果是故意的,如何强制 Python 在不使用 IPython 的情况下在守护线程中打印回溯?

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    根据 Wikipedia,根据定义,守护进程应该从控制 tty 中分离出来,所以我认为不显示异常是正确的(毕竟,即使关闭启动它的 shell,守护进程也应该继续工作)。 .
    here

    至于如何打印回溯,我认为一个简单的 try/except_then_log_to_file 就可以了:)

    【讨论】:

    • 您的解决方案非常适合打印回溯。我没想过尝试...除了因为我依赖 Python 来为我打印。顺便说一句,根据文档,我相信当程序退出时,守护线程会终止,而不仅仅是分离。感谢您的帮助!
    【解决方案2】:

    这是一个错误,还是我错过了文档中的某些内容并且这种行为是故意的?

    你自己基本上已经说出了原因,却不知不觉:

    根据文档,'daemon' 标志的唯一意义是“当只剩下守护线程时,整个 Python 程序退出。”

    如果你有一个非守护线程,Python 会在thread.start() 之后等待它。这种等待包括它所做的任何事情,包括引发和处理异常。

    如果你有一个守护线程,Python 不会在thread.start() 之后等待。相反,如果没有进一步的指令,Python 会立即退出。这意味着您的线程永远没有机会引发或处理异常。


    如果是故意的,如何强制 Python 在不使用 IPython 的情况下在守护线程中打印回溯?

    对于daemon 线程,您的线程应该做什么是无关紧要的。如果它被指示打印一些东西,也会发生同样的事情。

    这也意味着您无法有条件地等待守护程序的操作。您可以设置thread.daemon = False 并获取所有回溯——以及所有打印、I/O 和其他操作。或者你设置了thread.daemon = True 并且在所有其他线程都死了之后没有回溯 - 也没有打印、I/O 或其他操作。


    然而,有趣的是,如果我通过在 IPython shell 中导入代码来执行代码,无论线程是否为守护线程,都会显示异常。

    关于贝壳的事情是,除非你杀死它们,否则它们永远不会退出。由于 shell 的解释器在等待您的输入时不会退出,因此任何启动的 daemon 线程都保持活动状态。

    【讨论】: