繁体   English   中英

没有捕获Python 2.7自定义异常

[英]Python 2.7 custom exception is not being caught

我正在使用自定义超时异常来解决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

我没有输出超时消息并终止subProc,而是得到以下输出:

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

handle_timeout自超时以来似乎工作正常,但是异常处理被忽略或跳过。 我在语法方面做错了吗,还是需要在子进程中定义一个单独的自定义异常?

编辑:

之前的第二个代码块不完整。 这是当前存在的情况(包括chepner对iter(stdout.readline,'')不相关的建议):

from subprocess import Popen, PIPE
signal.signal(signal.SIGALRM, handle_timeout)
subProc = Popen(('tail', '-f', fileName), stdout=PIPE, stderr=PIPE, shell=False, close_fds=True)
for line in subProc.stdout:
    signal.alarm(CHILD_TIMEOUT)
    try:
        process_line(line)
    except Timeout as time_out:
        print(time_out.message)
        subProc.terminate()
        break

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

# 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_timeout将抓住该错误并每次重新引发它。 您不能在多个地方处理异常。 因为它有两个单独的函数试图同时处理同一错误。 这将始终产生冲突,并且第一个捕获错误的冲突将导致您的主进程退出。 您可以在此处执行几项不同的操作,但请允许我恳请您-不要无缘无故地吃掉错误。

修复1:删除您的错误处理程序

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

修复2:

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

以上将保证子进程的终止而不会产生错误。 另外,使用诸如handle_timeout处理程序之类的自定义句柄捕获错误是一种几乎专门用于在重新引发错误之前解构复杂运行或对象的技术。 它是最后一个解决方案,主要用于在发生特定错误后进行大量清理的情况。 如果要这样做,请不要使用except块。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM