Python多处理:在第一个子错误时中止映射

时间:2018-09-11 08:59:59

标签: python multiprocessing python-3.6

当一个孩子中止和/或抛出异常时中止多处理的正确方法是什么?

我发现了各种问题(generic multiprocessing error handlinghow to close multiprocessing pool on exception but without answer,...),但是对于如何在子异常上停止多处理并没有明确的答案。

例如,我需要以下代码:

def f(x):
    sleep(x)
    print(f"f({x})")
    return 1.0 / (x - 2)


def main():
    with Pool(4) as p:
        try:
            r = p.map(f, range(7))
        except Exception as e:
            print(f"oops: {e}")
            p.close()
            p.terminate()
    print("end")


if __name__ == '__main__':
    main()

要输出:

f(0)
f(1)
f(2)
oops: float division by zero
end

相反,它将在检测/处理异常之前对所有项目应用f函数:

f(0)
f(1)
f(2)
f(4)
f(3)
f(5)
f(6)
oops: float division by zero
end

有没有办法直接捕获异常?

1 个答案:

答案 0 :(得分:1)

我认为您为此需要apply_async,因此您可以根据每个结果而不是累积结果采取行动。 pool.apply_async提供了一个error_callback参数,您可以使用该参数来注册错误处理程序。 apply_async没有阻止,因此您需要join()池。我还使用标志terminated来知道何时可以正常处理结果,以防万一没有异常发生。

from time import sleep
from multiprocessing import Pool

def f(x):
    sleep(x)
    print(f"f({x})")
    return 1.0 / (x - 2)

def on_error(e):
    global terminated
    terminated = True
    pool.terminate()
    print(f"oops:{e}")


def main():
    global pool
    global terminated

    terminated = False

    pool = Pool(4)
    results = [pool.apply_async(f, (x,), error_callback=on_error)
               for x in range(7)]
    pool.close()
    pool.join()

    if not terminated:
        for r in results:
            print(r.get())

    print("end")


if __name__ == '__main__':
    main()