子进程子回溯

Posted

技术标签:

【中文标题】子进程子回溯【英文标题】:subprocess child traceback 【发布时间】:2016-11-20 21:22:57 【问题描述】:

我想访问在子进程中运行的 python 程序的回溯。

The documentation 说:

在新程序开始执行之前,子进程中引发的异常将在父进程中重新引发。此外,异常对象还有一个名为 child_traceback 的额外属性,它是一个字符串,包含从孩子的角度来看的回溯信息。

my_sub_program.py的内容:

raise Exception("I am raised!")

my_main_program.py的内容:

import sys
import subprocess
try:
    subprocess.check_output([sys.executable, "my_sub_program.py"])
except Exception as e:
    print e.child_traceback

如果我运行my_main_program.py,我会收到以下错误:

Traceback (most recent call last):
  File "my_main_program.py", line 6, in <module>
    print e.child_traceback
AttributeError: 'CalledProcessError' object has no attribute 'child_traceback'

如何在不修改子进程程序代码的情况下访问子进程的traceback?这意味着,我想避免在我的整个子程序代码周围添加一个大的 try/except 子句,而是从我的主程序处理错误日志记录。

编辑: sys.executable 应该可以替换为不同于运行主程序的解释器。

【问题讨论】:

文档说“在新程序开始执行之前”,在您的情况下,在执行新程序时引发了异常,因此没有child_traceback。新程序运行后,您需要捕获 CalledProcessError 异常并执行以下操作:***.com/questions/24849998/… using CalledProcessError.output 在我的例子中,CalledProcessError.output 只捕获标准输出,但没有捕获异常的回溯。 这可能是因为输出是在stderr 上发送的。查看我通过上面的链接发送给您的问题的答案,了解更多详情 【参考方案1】:

当您开始另一个 Python 进程时,您也可以尝试使用 multiprocessing Python 模块;通过对Process 类进行子类化,很容易从目标函数中获取异常:

from multiprocessing import Process, Pipe
import traceback
import functools

class MyProcess(Process):
    def __init__(self, *args, **kwargs):
        Process.__init__(self, *args, **kwargs)
        self._pconn, self._cconn = Pipe()
        self._exception = None

    def run(self):
        try:
            Process.run(self)
            self._cconn.send(None)
        except Exception as e:
            tb = traceback.format_exc()
            self._cconn.send((e, tb))
            # raise e  # You can still rise this exception if you need to

    @property
    def exception(self):
        if self._pconn.poll():
            self._exception = self._pconn.recv()
        return self._exception


p = MyProcess(target=functools.partial(execfile, "my_sub_program.py"))
p.start()
p.join() #wait for sub-process to end

if p.exception:
    error, traceback = p.exception
    print 'you got', traceback

诀窍是让目标函数执行 Python 子程序,这是通过使用 functools.partial 来完成的。

【讨论】:

此解决方案是否允许子进程在与主程序不同的解释器中运行?当我看到您的建议时,我注意到在我的示例中使用 sys.executable 具有误导性。但是,在我的问题的上下文中,我需要在主进程之外的另一个虚拟环境中启动脚本。 (主进程将是某种调度程序) 其实multiprocessing是在POSIX平台上做os.fork的,所以不是新的虚拟环境;但是,您可以通过尽早启动 Process 对象来限制进程之间共享数据的数量,这可能足以满足您的需求 如果你正在做一种调度程序,为什么不使用类似Celery

以上是关于子进程子回溯的主要内容,如果未能解决你的问题,请参考以下文章

Linux学习-进程管理

Shell脚本入门 07:进程与信号

Shell脚本入门 07:进程与信号

关于wait 和 exit

创建一个不是创建进程子进程的新进程

38父进程子进程进程组作业和会话