在Python中打印Daemonic Thread Exceptions

时间:2009-05-17 20:45:29

标签: python multithreading

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中导入代码来执行代码,则会显示该线程是否为守护进程的异常。

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

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

2 个答案:

答案 0 :(得分:6)

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

至于如何打印回溯,我认为一个简单的try / except_then_log_to_file可以解决这个问题:)

答案 1 :(得分:0)

  

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

您基本上是自己说出原因的,而没有意识到:

  

根据文档,“ daemon”标志的唯一含义是“仅保留守护程序线程时,整个Python程序都会退出。”

如果您有非守护线程,Python将在thread.start()之后等待它。这种等待包括它所做的一切,包括引发和处理异常。

如果您有守护线程,则Python {em>不会在thread.start()之后等待。相反,在没有其他说明的情况下,Python立即退出。这意味着您的线程将永远没有机会引发或处理异常。


  

如果是故意的,我如何不使用IPython强制Python在后台驻留程序线程中打印回溯?

对于daemon线程,线程应该执行的操作无关紧要。如果指示打印某些内容,则同样会发生。

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


  

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

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

相关问题