我使用pool.apply_async
在Python中使用多处理,同时运行具有各种不同参数的函数。
代码的相关摘录是:
import multiprocessing as mp
all_details_to_process_full = [[x,y.z], [x2,y2.z2]]
def loop_over_desired_sub(arg_list):
...
if __name__ == '__main__':
pool = mp.Pool(processes=10)
desired_content = [pool.apply_async(loop_over_desired_sub, args=(arg_list,)) for arg_list in all_details_to_process_full]
results = [p.get() for p in desired_content]
据我所知,默认行为是Python只在最初初始化的子进程引发错误时停止代码。
例如,如果列表中有10个项目要处理单独的子进程,并且处理第一个项目(即初始化的第一个子进程)时出错,Python将立即引发错误,停止代码。但是,如果第二个子进程中存在错误,而该子进程将停止,则其余代码将继续执行,直到第一个项目完成,此时错误将被引发并且代码停止。 [如果在处理第三项时出现错误,则在引发错误之前,第一项和第二项都需要完成]。
是否有办法改变这种行为,包括:
引发任何错误,即在任何子进程中,以停止代码 立即
如果出现错误,代码不会停止,直到全部 子处理已完成
答案 0 :(得分:2)
当您使用apply_async
时,您的每个流程都是独立的。因此,python的默认行为是独立处理它们,这意味着一个失败不会影响另一个'
这里的问题是您以有序的方式处理函数loop_over_desired_content
的结果。
get
方法将被阻塞,直到检索到第一个操作的结果(即使第二个进程返回/失败)。然后,它将处理第二个值,如果需要则引发错误。
import multiprocessing as mp
import time
def fail_in(args):
x, l = args
if x == l:
raise RuntimeError(x)
time.sleep(.5)
print("Finish process {}".format(x))
return x
if __name__ == '__main__':
pool = mp.Pool(processes=3)
tasks = [(i, 0) for i in range(9)]
try:
desired_content = [pool.apply_async(fail_in, args=(a,)) for a in tasks]
t1 = time.time()
results = [p.get() for p in desired_content]
except RuntimeError:
print("apply_async 0 failed in {:4.2}s".format(time.time()-t1))
pool.terminate()
pool = mp.Pool(processes=3)
tasks = [(i, 1) for i in range(9)]
try:
desired_content = [pool.apply_async(fail_in, args=(a,)) for a in tasks]
t1 = time.time()
results = [p.get() for p in desired_content]
except RuntimeError:
print("apply_async 1 failed in {:4.2}s".format(time.time()-t1))
pool.terminate()
pool = mp.Pool(processes=3)
tasks = [(i, 4) for i in range(9)]
try:
desired_content = [pool.apply_async(fail_in, args=(a,)) for a in tasks]
t1 = time.time()
results = [p.get() for p in desired_content]
except RuntimeError:
print("apply_async 4 failed in {:4.2}s".format(time.time()-t1))
pool.terminate()
请注意,此错误不会终止剩余进程。您可以通过尝试在池中提交新作业而不使用terminate
来查看它。他们将在您上一份工作的所有剩余流程完成后启动。
要获得更快的错误通知,您可以使用方法imap_unordered
,这会在错误返回时立即引发错误。您需要小心,因为您需要使用job_id来找回订单
在这种情况下,您还可以使用callback_error
获取通知以执行清理。
对于第二个行为者,在提出错误之前要求所有结果进行处理,您可以使用:
desired_content = [pool.apply_async(loop_over_desired_sub, args=(arg_list,))
for arg_list in all_details_to_process_full]
results = []
for p in desired_content:
try:
r = p.get()
except Exception as r:
pass
results += [r]
results = [p.get() for p in desired_content]