从子流程重新评估异常



我在一个子流程中执行的代码本应引发异常。

当从子流程返回异常时(最好是在保留堆栈跟踪的情况下),我想在主流程中引发相同的异常,但我不确定如何做到这一点。

我从子流程中捕获stderr很好,但我找不到如何解析它,所以我得到了异常的类型。我该如何做到这一点?

我正在使用python 2.7

主要方法

import subprocess
example=subprocess.Popen(["python","example.py"],
                                    stdout = subprocess.PIPE,
                                    stderr = subprocess.PIPE)
return_obj, return_error = example.communicate()
if return_error:
# replace with error from subprocess
  print "Should raise ",NameError('HiThere')
  raise TypeError('Wrong type')

子流程

raise NameError('HiThere')

如果您只想让python代码在单独的进程中运行,那么您可能不应该使用subprocess。正如Serge Ballesta所说,subprocess的目的是在操作系统级别运行一个不同的程序,而不必特别关心它是什么——没有什么可以帮助你正确处理python解释器过程的复杂性。

出于这种目的,最好简单地import您的代码并使用multiprocessing,它公开了一个高级接口来帮助您在多个进程中运行python代码。

假设您在example.py:上有一个定义良好的main函数

from examply import main as example_main
import multiprocessing
pool= multiprocessing.Pool(1)
pool.apply( example_main )

使用此代码,异常和返回值都将透明地提供给主进程。

如果您不想阻止等待结果,也可以使用Pool.apply_async

子流程执行不同的本机应用程序。它可以是java、C++、lisp,甚至Fortran或Cobol。因此,只有两种方法可以从Python子流程中获取异常:

  • 完全忘记子流程,直接在同一个python程序中调用python代码,只需简单的try except即可完成工作
  • 在主进程和子进程之间的接口契约中定义,例如,如果没有发生致命的exeption,则要求错误输出必须为空,否则包含异常和堆栈争用的pickle

如果两个进程都是python进程,并且必须使用管道,则可以通过管道序列化异常对象。

来电者:

parent_conn.send(event)
result = parent_conn.recv()
if isinstance(result, Exception):
    raise result
else:
    return result

接收器:

def subprocess_loop(parent_conn, child_conn):
    
    parent_conn.close()
    while True:
        event = child_conn.recv()
        try:
            result = event_handler(event)
        except Exception as exc:
            child_conn.send(exc)
            continue
        child_conn.send(result)

接收器进程创建:

parent_conn, child_conn = Pipe()
process = Process(target=subprocess_loop, args=(parent_conn, child_conn))
process.start()
child_conn.close()

最新更新