Python多处理 - 在发生未处理的异常时正常退出

时间:2016-08-10 13:51:00

标签: python exception multiprocessing unhandled

我的多处理程序尝试处理进程中的异常的逻辑非常类似于以下内容:

import multiprocessing

class CriticalError(Exception):

    def __init__(self, error_message):
        print error_message
        q.put("exit")


def foo_process():
    while True:
        try:
            line = open("a_file_that_does_not_exist").readline()
        except IOError:
            raise CriticalError("IOError")

        try:
            text = line.split(',')[1]
            print text
        except IndexError:
            print 'no text'

if __name__ == "__main__":
    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=foo_process)
    p.start()

    while True:
        if not q.empty():
            msg = q.get()
            if msg == "exit":
                p.terminate()
                exit()

如果我没有尝试 - 除了文件操作,我得到

Traceback (most recent call last):
  File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "foo.py", line 22, in foo_process
    line = open("a_file_that_does_not_exist").readline()
IOError: [Errno 2] No such file or directory: 'a_file_that_does_not_exist'

但该计划仍然开放。有没有Pythonic方法来删除try-except 与IOError相关的子句,或实际上,也包含所有未处理的异常 把"退出"消息进入队列' q',或者终止进程并退出 以其他方式编程?当我这时,这将大大清除我的代码库 不必捕获在没有多处理的应用程序中自动杀死程序的错误。 它还允许我在AssertionError时添加断言 退出程序。无论解决方案是什么,我都希望能够看到 追溯 - 我目前的解决方案并没有提供它。

1 个答案:

答案 0 :(得分:0)

由于孩子无论如何都会因异常而死(即p.terminate()毫无意义),为什么不让主进程检查其子女是否还活着?

from queue import Empty
# from Queue import Empty  # if Python 2.x

while not q.empty():
    if not p.is_alive():
        break

    try:
        msg = q.get(timeout=1)
    except Empty:
        continue

    # other message handling code goes here

# some graceful cleanup
exit()

请注意,我已在get添加了超时,因此当孩子死亡时,它不会永久阻止。您可以根据需要自定义时间段。

因此,您不需要在子进程中执行任何异常操作,例如在出错时推送到队列。除了原始方法在某些罕见的情况下会失败,例如强制杀死孩子将导致主人永远挂起(导致孩子没有时间将任何东西推到队列中)。

您可以通过在sys.stdout函数内重新绑定sys.stderr(和/或foo_process)(到父级stdout或文件或其他任何内容,从子进程中检索回溯文件描述符支持)。看看这里:

Log output of multiprocessing.Process

如果没有队列和多个进程,我会选择类似的东西:

processes = [f, b, c]
while processes:
    time.sleep(1)
    for p in processes:
        if not p.is_alive():
            processes.remove(p)
            break
exit()

可以通过连接更好地完成:

processes = [f, b, c]
for p in processes:
    p.join()
exit()

假设主人在等待孩子时不应该做任何其他事情。