繁体   English   中英

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

[英]Python multiprocessing - graceful exit when an unhandled exception occurs

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

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()

如果我没有关于文件操作的try-except,我会得到

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'

但是该程序仍处于打开状态。 是否有Python方式删除与IOError相关的try-except子句,或者实际上使所有未处理的异常都将“退出”消息放入队列“ q”,或终止进程并以其他方式退出程序? 当我不必捕获没有多处理的应用程序中的错误时,这将极大地清除我的代码库。 当AssertionError也将退出程序时,它还允许我添加断言。 无论采用哪种解决方案,我都希望能够看到回溯-我当前的解决方案不提供它。

由于孩子仍然会因异常而死亡(即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上添加了超时,因此在孩子死后它不会永远阻塞。 您可以根据需要自定义时间段。

这样,您就不需要在子进程中执行任何异常操作,例如将错误推送到队列中。 此外,原始方法在极少数情况下会失败,例如,强行杀死孩子会导致主人永远吊死(因为孩子没有时间将任何东西推到队列中)。

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

多处理的日志输出


没有队列并且有多个进程,我会选择类似的东西:

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

使用join可以做得更好:

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

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

暂无
暂无

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

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