How Python multiprocessing captures exceptions thrown by child processes in the main process, applicable to Child process has no return value The scene.
Recommend using a multiprocessing based approach The solution for Queue().
Option 1:
Based on multiprocessing Queue() implements the communication of error messages between the child process and the main process. If the child process throws an exception, the error message_The put (error_flag= 1) flag bit in the queue, otherwise put (error_flag= None), call error in the main process_Flag; Error_Queue. get(), if there is an error_Flag= None, indicating that an exception has been thrown in the child process, the loop calls terminate() and join() to terminate All Child process, and call sys. exit (1) to exit the main process, otherwise call join() to wait for the child process to finish running.
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()#implement error message communication between child processes and main processes
for idx in range(0, paralCnt):
args.append((idx, error_queue))
processList = multiProcessor_start(foo, args)
queue_length = 0#record error_queue in get arrived error_flag the number of
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()#terminate all child processes
sys.exit(1)#terminate the main process
if queue_length >= paralCnt:
for p in processList:
p.join()
print("mission succeed")
sys.exit(1)
if __name__=='__main__':
main()
Option 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()#implement error message communication between child processes and main processes
for idx in range(0, paralCnt):
args.append((idx, error_queue))
processList = multiProcessor_start(foo, args)
queue_length = 0#record error_queue in get arrived error_flag the number of
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()#terminate all child processes
sys.exit(1)#terminate the main process
if queue_length >= paralCnt:
for p in processList:
p.join()
print("mission succeed")
sys.exit(1)
if __name__=='__main__':
main()
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) #send anomalies out through pipelines
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() #if the child process does not throw an exception, accept the value. otherwise, the main process exits to avoid being blocked by the pipeline !
#print (child_return)
except Exception as e:
print(e)