当我的脚本运行时,某些时候可能会发生错误。在这种情况下,应正确终止所有进程,返回错误消息,并退出脚本。
我现在的代码似乎还没有满足这些要求。发生错误时,会将其发送到report_error()
,脚本最终会挂在终端中,而Activity Monitor会显示许多Python进程仍在运行。
环境
从脚本中的任何一点终止所有进程的正确方法是什么?
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from multiprocessing import Pool
# Global variables.
input_files = [
'test_data_0.csv',
'test_data_1.csv'
]
def report_error(error):
# Reports errors then exits script.
print("Error: {0}".format(error), file=sys.stderr)
sys.exit(1)
# What I really want is to report the error, properly terminate all processes,
# and then exit the script.
def read_file(file):
try:
# Read file into list.
except Exception as error:
report_error(error)
def check_file(file):
# Do some error checking on file.
if error:
report_error(error)
def job(file):
# Executed on each item in input_files.
check_file(file)
read_file(file)
def main():
# Sets up a process pool. Defaults to number of cores.
# Each input gets passed to job and processed in a separate process.
p = Pool()
p.map(job, input_files)
# Closing and joining a pool is important to ensure all resources are freed properly.
p.close()
p.join()
if __name__ == '__main__':
main()
答案 0 :(得分:4)
首先,使用sys.exit()
来终止子工作进程实际上会破坏池,并使map
命令永远挂起。当工作人员正在处理作业时,当前multiprocessing
无法从工作进程中的崩溃中正常恢复(有一个错误报告带有解决此问题的补丁here,其价值)
您可以通过多种方式执行实际想要做的事情。由于您似乎并不关心从工作函数返回的值,因此最简单的方法是使用imap_unordered
而不是map
,在工作人员处理时会引发异常。 sa失败,然后简单地迭代imap_unordered
返回的迭代器:
def report_error(error):
# Reports errors then exits script.
print("Error: {0}".format(error), file=sys.stderr)
raise error # Raise the exception
...
def main():
p = Pool()
try:
list(p.imap_unordered(job, input_files))
except Exception:
print("a worker failed, aborting...")
p.close()
p.terminate()
else:
p.close()
p.join()
if __name__ == '__main__':
main()
使用imap_unordered
,结果将在孩子发送后立即返回给父母。因此,如果子项将异常发送回父级,它将立即在父进程中重新引发。我们捕获该异常,打印消息,然后终止池。