【python】多进程异常处理【multiprocessing】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lixiaowang_327/article/details/81319923

python multiprocessing 如何在主进程中捕获子进程抛出的异常,适用于子进程无返回值的场景。

推荐使用基于 multiprocessing.Queue() 的方案。

方案 1:

基于 multiprocessing.Queue() 实现子进程和主进程之间报错信息的通信,如果子进程抛出异常,就在 error_queue 队列中 put(error_flag=1) 标志位,否则 put(error_flag=None),在主进程中调用 error_flag=error_queue.get(),如果 error_flag != None,说明子进程中抛出了异常,则循环调用 terminate() 、join() 终止所有子进程,并调用 sys.exit(1) 退出主进程,否则调用 join() 等待子进程运行完毕。

import multiprocessing
from time import sleep
import sys

def foo(i, error_queue): 
    try: 
        print("idx : %1d" % i) 
        print(1 / (float(i) - 3))        
        error_queue.put(None)
        sleep(2)
    except Exception as e:
        error_queue.put(e)

def multiProcessor_start(func, args):
    ProcessCnt = len(args)
    processList = []
    for idx in range(0,ProcessCnt):
        processList.append(multiprocessing.Process(target = func, args = args[idx]))    
    for idx in range(0,ProcessCnt):
        processList[idx].start()
    return processList

def main(paralCnt = 15):
    args = []
    error_queue = multiprocessing.Queue()#实现子进程和主进程之间的报错信息通信
    for idx in range(0, paralCnt):
        args.append((idx, error_queue))
    processList = multiProcessor_start(foo, args)
    queue_length = 0#记录error_queue中get到的error_flag的个数
    while True:
        if not error_queue.empty():
            error_flag = error_queue.get()
            queue_length += 1
            if error_flag != None:
                print(error_flag)
                for p in processList:
                    p.terminate()
                    p.join()#终止所有子进程
                sys.exit(1)#终止主进程
            if queue_length >= paralCnt:
                for p in processList:
                    p.join()
                print("mission succeed")               
                sys.exit(1)

if __name__=='__main__':
    main()

方案 2:

import multiprocessing
from time import sleep
import sys

def foo(i, error_queue): 

    try: 
        print("idx : %1d" % i) 
        print(1 / (float(i) - 3))        
        sleep(2)
    except Exception as e:
        error_queue.put(1)
        return

    try: 
        print("idx : %1d" % i) 
        print(1 / (float(i) + 3))        
        sleep(2)
    except Exception as e:
        error_queue.put(1)
        return

    error_queue.put(None)

def multiProcessor_start(func, args):
    ProcessCnt = len(args)
    processList = []
    for idx in range(0,ProcessCnt):
        processList.append(multiprocessing.Process(target = func, args = args[idx]))    
    for idx in range(0,ProcessCnt):
        processList[idx].start()
    return processList

def main(paralCnt = 15):
    args = []
    error_queue = multiprocessing.Queue()#实现子进程和主进程之间的报错信息通信
    for idx in range(0, paralCnt):
        args.append((idx, error_queue))
    processList = multiProcessor_start(foo, args)
    queue_length = 0#记录error_queue中get到的error_flag的个数
    while True:
        if not error_queue.empty():
            error_flag = error_queue.get()
            queue_length += 1
            if error_flag != None:
                print(error_flag)
                for p in processList:
                    p.terminate()
                    p.join()#终止所有子进程
                sys.exit(1)#终止主进程
            if queue_length >= paralCnt:
                for p in processList:
                    p.join()
                print("mission succeed")               
                sys.exit(1)

if __name__=='__main__':
    main()

方案 3:(改进自参考文献 1)

import multiprocessing
import traceback

class Process(multiprocessing.Process):
    def __init__(self, *args, **kwargs):
        multiprocessing.Process.__init__(self, *args, **kwargs)
        self._pconn, self._cconn = multiprocessing.Pipe()
        self._exception = None
    def run(self):
        try:
            multiprocessing.Process.run(self)
            self._cconn.send(None)
        except Exception as e:
            tb = traceback.format_exc()
            self._cconn.send((e, tb))
    @property
    def exception(self):
        if self._pconn.poll():#.poll(): return whether there is any data avaliable to read
            self._exception = self._pconn.recv()
        return self._exception

def heavy_load_func(i): 
#    try:
#    child_conn.send(return_value)  #return something  
    print("this is heavy_load_func")  
    raise ValueError("[child process]:something wrong.")   
#    except Exception as e:
#        child_conn.send(e)  #将异常通过管道送出

if __name__=='__main__':
    try:
        #_, child_conn = multiprocessing.Pipe()
        #child_process = multiprocessing.Process(target=heavy_load_func, args=(10, child_conn))
        child_process = Process(target=heavy_load_func, args=(1,))
        child_process.start()
        child_process.join()
        if child_process.exception:
            error, traceback = child_process.exception
            print(error)
            child_process.terminate()#terminate the process
        else:
            print("mission succeed")
            #child_return = parent_conn.recv()  #如果不子进程不抛出异常就接受值,否则主进程退出,避免主进程被管道阻塞!
            #print (child_return)
    except Exception as e:
        print(e)

参考文献 1:https://www.cnblogs.com/liujshi/p/6014521.html

参考文献 2:http://www.liujiangblog.com/course/python/82

猜你喜欢

转载自blog.csdn.net/lixiaowang_327/article/details/81319923
今日推荐