未捕获Python 2.7自定义异常

未捕获Python 2.7自定义异常,python,Python,我正在使用一个自定义超时异常来绕过iter(subprocess.Popen.stdout.readline“”)阻塞,因为没有更多的输出可读取,但异常没有被正确捕获。这是一段既有主进程又有单独进程(用multiprocessing.process实现)的代码,其中任何一个进程都可能发生超时。有关章节包括: class Timeout(Exception): def __init__(self, message): self.message = message def

我正在使用一个自定义超时异常来绕过iter(subprocess.Popen.stdout.readline“”)阻塞,因为没有更多的输出可读取,但异常没有被正确捕获。这是一段既有主进程又有单独进程(用multiprocessing.process实现)的代码,其中任何一个进程都可能发生超时。有关章节包括:

class Timeout(Exception):
    def __init__(self, message):
        self.message = message

def handle_timeout(signal, frame):
    raise Timeout("Timed out")
此自定义异常在主进程中捕获得很好,但在子进程中,无论何时引发超时,都不会捕获它,尽管使用了(我相信)适当的标准语法:

from subprocess import Popen, PIPE
subProc = Popen(('tail', '-f', fileName), stdout=PIPE, stderr=PIPE, shell=False, close_fds=True)
lines = iter(subProc.stdout.readline,'')
for line in lines:
    try:
        process_line(line)
    except Timeout as time_out:
        print(time_out.message)
        subProc.terminate()
        break
我没有打印超时消息和终止子程序,而是得到以下输出:

Traceback (most recent call last):
  File "/home/username/anaconda2/envs/Py2.7/lib/python2.7/multiprocessing/process.py", line 267, in _bootstrap
    self.run()
  File "reader.py", line 50, in run
    for line in lines:
  File "reader.py", line 13, in handle_timeout
    raise Timeout("Timed out")
Timeout
句柄\u超时似乎工作正常,因为超时被引发,但异常处理被忽略或跳过。我是否在语法方面做了任何错误的事情,或者我是否需要定义一个单独的自定义异常(可能在子进程中)

编辑:

之前的第二个代码块不完整。这就是目前存在的情况(包括切普纳关于国际热核实验堆无关性的建议(stdout.readline“”):

在父进程中(超时异常完全按照需要工作),格式为:

# signal masking as in last block
while True:
    try:
        signal.alarm(MASTER_TIMEOUT) # different from CHILD_TIMEOUT
        other_processing()
    except Timeout:
        shutDown(children) # method to shut down child processes
        break
已解决:

我找到了解决办法

subProc = Popen(('tail', '-f', fileName), stdout=PIPE, stderr=PIPE, shell=False, close_fds=True)
while not exit.is_set(): # exit is defined by multiprocessing.Event()
    signal.alarm(3)
    try:
        for line in subProc.stdout:
            process_line(line)
    except Timeout:
        print("Process timed out while waiting for log output")
        subProc.terminate()
        exit.set()

现在,当警报响起时,超时异常会被触发并捕获,在触发退出条件之前结束子进程,然后子进程会正常关闭。

您不能像处理代码那样在子进程中捕获错误。您所认为的使用事件捕获的错误处理或不使用事件捕获的错误处理实际上是正在引发的子流程,执行代码并管理响应。由于您使用popopen手动控制子流程,因此需要手动处理其响应

子流程结束时,应返回0。如果返回-1或1,则表示发生了错误,需要从stderr读取以捕获错误

Edit1

我明白你的问题了。您编写处理程序
handle\u timeout
的方式将捕获错误并每次重新引发它。不能在多个位置处理异常。实际上,您有两个单独的函数试图同时处理同一个错误。这将始终产生冲突,第一个捕获错误的进程将导致主进程退出。你可以在这里做一些不同的事情,但我恳求你——不要无缘无故地承认错误

修正1: 删除错误处理程序

def handle_timeout(signal, frame):
    raise Timeout("Timed out")
修正2:

try:
    process_line(line)
finally: 
    subProc.terminate()

上述操作将保证子进程的终止不会产生错误。此外,使用诸如句柄\超时处理程序之类的自定义句柄捕获错误几乎是一种专门用于在重新引发错误之前解构复杂运行或对象的技术。这是一个最后的解决方案,基本上适用于在发生特定错误后进行大量清理的情况。如果要执行此操作,请不要使用
except

在另一个进程中引发的超时(或任何其他)异常需要在该进程中捕获和处理,但我无法从代码中判断您在该进程中做什么。如果程序只是将异常打印到控制台并继续,那么它几乎肯定会在另一个进程中发生。如果这不是问题,那么快速阅读可能会有所帮助。
subProc.stdout
已经是一个iterable;你不需要打电话给iter来做一个。@chepner谢谢;我以前很少使用子进程。因此,如果我理解正确,由于正在运行的子进程,“try:…except Timeout:…”块会被忽略吗?如果我不清楚这一点:子进程本身(tail-f)在任何时候都不会抛出错误。引发但(显然)被忽略的异常在python脚本的子进程中,而不是在使用Popen创建的子进程中(因为Popen是非阻塞的,并且它生成的进程有一个单独的PID,我不希望它中断错误处理),如果在子进程关闭后阅读stderr,它是否包含任何内容?好的,我知道发生了什么。看看我的编辑。看看我刚刚做的编辑。handle_timeout()是一个在每个进程中屏蔽SIGALRM的函数,它在引发超时异常后不会处理超时异常(不过,我现在意识到这个名称有多么误导)。在这段代码中,除了handle_timeout之外,没有任何东西会引发超时(并且仅当进程接收到signal.SIGALRM时)。这两个进程中的超时不会同时发生。如果它在引发错误后重新引发错误,我希望它在父进程中也会失败,但在那里它可以正常工作。我已经做了您在修复2中建议的更改,它会中断子进程。finally块在try之后立即执行,在日志文件仍在写入时关闭子进程(我不希望一次tail调用;我希望它继续执行),只需几秒钟,主进程就没有输出(如果timeout保持不变,但仅针对主进程,则超时并结束程序;如果没有超时,则挂起)。
try:
    process_line(line)
finally: 
    subProc.terminate()