简体   繁体   English

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

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

The logic of my multiprocessing program that tries to handle exceptions in processes is pretty much like the following: 我的尝试处理进程中异常的多处理程序的逻辑非常类似于以下内容:

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

If I don't have the try-except around file operation, I get 如果我没有关于文件操作的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'

but the program remains open. 但是该程序仍处于打开状态。 Is there a Pythonic way to remove the try-except clause related to IOError, or actually, to have all unhandled exceptions either put the "exit" message into Queue 'q', or terminate the process and exit the program some other way? 是否有Python方式删除与IOError相关的try-except子句,或者实际上使所有未处理的异常都将“退出”消息放入队列“ q”,或终止进程并以其他方式退出程序? This would clear my codebase by a huge amount when I wouldn't have to catch errors that in applications without multiprocessing kill the program automatically. 当我不必捕获没有多处理的应用程序中的错误时,这将极大地清除我的代码库。 It would also allow me to add assertions when AssertionError would also exit the program. 当AssertionError也将退出程序时,它还允许我添加断言。 Whatever the solution, I'd like to be able to see the traceback -- my current solution doesn't provide it. 无论采用哪种解决方案,我都希望能够看到回溯-我当前的解决方案不提供它。

Since the child will die on exception anyway (ie p.terminate() is pointless) then why not let the master process check if its child is still alive? 由于孩子仍然会因异常而死亡(即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()

Note that I've added timeout on get so it won't block forever when the child is dead. 请注意,我在get上添加了超时,因此在孩子死后它不会永远阻塞。 You can customize the period to your needs. 您可以根据需要自定义时间段。

With that you don't need to do anything unusual in the child process like pushing to a queue on error. 这样,您就不需要在子进程中执行任何异常操作,例如将错误推送到队列中。 Besides the original approach will fail on some rare occasions, eg force kill on the child will cause the master to hang forever (cause child won't have time to push anything to the queue). 此外,原始方法在极少数情况下会失败,例如,强行杀死孩子会导致主人永远吊死(因为孩子没有时间将任何东西推到队列中)。

You can potentially retrieve traceback from the child process by rebinding sys.stdout (and/or sys.stderr ) inside foo_process function (to either parent's stdout or a file or whatever file descriptors support). 通过将foo_process函数内的sys.stdout (和/或sys.stderr )重新绑定(绑定到父级的stdout或文件或任何文件描述符支持的),可以潜在地从子进程中检索回溯。 Have a look here: 在这里看看:

Log output of multiprocessing.Process 多处理的日志输出


Without queue and with multiple processes I would go for something like that: 没有队列并且有多个进程,我会选择类似的东西:

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

which can be done better with joins: 使用join可以做得更好:

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

assuming that master is not supposed to do anything else while waiting for children. 假设主人在等待孩子时不做任何其他事情。

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

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