版权声明:本文为博主原创文章,未经博主允许不得转载。 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)