当我尝试在目标函数抛出错误时退出多处理脚本,但父进程只是挂起而不是退出。
这是我用来复制问题的测试脚本:
#!/usr/bin/python3.5
import time, multiprocessing as mp
def myWait(wait, resultQueue):
startedAt = time.strftime("%H:%M:%S", time.localtime())
time.sleep(wait)
endedAt = time.strftime("%H:%M:%S", time.localtime())
name = mp.current_process().name
resultQueue.put((name, wait, startedAt, endedAt))
# queue initialisation
resultQueue = mp.Queue()
# process creation arg: (process number, sleep time, queue)
proc = [
mp.Process(target=myWait, name = ' _One_', args=(2, resultQueue,)),
mp.Process(target=myWait, name = ' _Two_', args=(2, resultQueue,))
]
# starting processes
for p in proc:
p.start()
for p in proc:
p.join()
# print results
results = {}
for p in proc:
name, wait, startedAt, endedAt = resultQueue.get()
print('Process %s started at %s wait %s ended at %s' % (name, startedAt, wait, endedAt))
这很好用,我可以看到父脚本在htop
中产生了两个子进程,但是当我想强制父脚本在myWait
目标函数中抛出错误时退出进程只是挂起,甚至不会产生任何子进程。我必须ctrl-c
来杀死它。
def myWait(wait, resultQueue):
try:
# do something wrong
except:
raise SystemExit
我已尝试各种方式退出该功能(例如exit()
,sys.exit()
,os._exit()
...)无济于事。
答案 0 :(得分:2)
首先,您的代码存在一个主要问题:您在刷新队列内容(如果有)之前尝试加入进程,这可能会导致死锁。请参阅标题为'加入使用队列的流程'在这里:https://docs.python.org/3/library/multiprocessing.html#multiprocessing-programming
其次,对resultQueue.get()
的调用将阻塞,直到它收到一些从未发生过的数据
如果从myWait
函数引发异常,并且在此之前没有数据被推入队列。因此,将其设置为非阻塞,并使其检查循环中的任何数据,直到它最终收到某些内容或某些错误。
这是一个快速的解决方案,可以提供您的想法:
#!/usr/bin/python3.5
import multiprocessing as mp
import queue
import time
def myWait(wait, resultQueue):
raise Exception("error!")
# queue initialisation
resultQueue = mp.Queue()
# process creation arg: (process number, sleep time, queue)
proc = [
mp.Process(target=myWait, name = ' _One_', args=(2, resultQueue,)),
mp.Process(target=myWait, name = ' _Two_', args=(2, resultQueue,))
]
# starting processes
for p in proc:
p.start()
# print results
results = {}
for p in proc:
while True:
if not p.is_alive():
break
try:
name, wait, startedAt, endedAt = resultQueue.get(block=False)
print('Process %s started at %s wait %s ended at %s'
% (name, startedAt, wait, endedAt))
break
except queue.Empty:
pass
for p in proc:
p.join()
函数myWait
将抛出异常,但两个进程仍然会加入,程序将很好地退出。
答案 1 :(得分:1)
您应该使用multiprocessing.Pool
来管理您的流程。然后使用Pool.imap_unordered
按结果顺序迭代结果。一旦获得第一个异常,就可以停止池及其子进程(退出with Pool() as pool
块时会自动完成)。例如
from multiprocessing import Pool
import time
def my_wait(args):
name, wait = args
if wait == 2:
raise ValueError("error!")
else:
startedAt = time.strftime("%H:%M:%S", time.localtime())
time.sleep(wait)
endedAt = time.strftime("%H:%M:%S", time.localtime())
return name, wait, startedAt, endedAt
if __name__ == "__main__":
try:
with Pool() as pool:
args = [["_One_", 2], ["_Two_", 3]]
for name, wait, startedAt, endedAt in pool.imap_unordered(my_wait, args):
print('Task %s started at %s wait %s ended at %s' % (name,
startedAt, wait, endedAt))
except ValueError as e:
print(e)
此方法不适用于长时间,低工作负载的任务,因为它只会像管理的子进程数一样并行运行许多任务(但这是您可以设置的)。如果你需要运行不同的功能,这也不是很好。