我有一个ProcessPoolExecutor,想在其中引发一个自定义异常。但是,只有当它具有默认参数或在超级初始化中使用或绕过该超级初始化功能时,它才有效而不会破坏进程池。
我对此行为一无所知。
在Py3.7和3.8上显示:
A process in the process pool was terminated abruptly while the future was running or pending.
有任何想法吗?
from concurrent.futures.process import ProcessPoolExecutor
class PoolBreaker(Exception):
def __init__(self, num):
super().__init__()
self.num = num
class NoPoolBreaker(Exception):
def __init__(self, num=0):
super().__init__()
self.num = num
class NoPoolBreaker2(Exception):
def __init__(self, num):
super().__init__(num)
self.num = num
class NoPoolBreaker3(Exception):
def __init__(self, num):
self.num = num
def get_result(job):
exc = job.exception()
if type(exc) is PoolBreaker:
print("PoolBreaker", exc.num)
elif type(exc) is NoPoolBreaker:
print("NoPoolBreaker", exc.num)
elif type(exc) is NoPoolBreaker2:
print("NoPoolBreaker2", exc.num)
elif type(exc) is NoPoolBreaker3:
print("NoPoolBreaker3", exc.num)
else:
print(f"Exception: {str(exc)}")
def work(x: int):
if x == 0:
raise PoolBreaker(x)
elif x == 1:
raise NoPoolBreaker(x)
elif x == 2:
raise NoPoolBreaker2(x)
elif x == 3:
raise NoPoolBreaker3(x)
if __name__ == '__main__':
for num in range(0, 4):
with ProcessPoolExecutor() as executor:
job = executor.submit(work, num)
get_result(job)
答案 0 :(得分:0)
我也解决了这个问题,对此我感到非常困惑。这只会在ProcessPoolExecutor中发生,而不会在ThreadPoolExecutor中发生。
问题是ProcessPoolExecutor尝试通过第二次创建来创建Exception的副本。为此,ProcessPoolExecutor似乎要检查“上层”类,例如NoPoolBreaker3除外,其中上层类是NoPoolBreaker3本身–属性。由于Exception并不总是拥有整个对象的所有属性,因此它会失败。
如果将打印品添加到构造函数中,您将看到:
from concurrent.futures.process import ProcessPoolExecutor
class PoolBreaker(Exception):
def __init__(self, num):
super().__init__()
print(f"PoolBreaker Constructor with num={num}")
self.num = num
class NoPoolBreaker1(Exception):
def __init__(self, num=-9):
super().__init__()
print(f"NoPoolBreaker1 Constructor with num={num}")
self.num = num
class NoPoolBreaker2(Exception):
def __init__(self, num):
super().__init__(num)
print(f"NoPoolBreaker2 Constructor with num={num}")
self.num = num
class NoPoolBreaker3(Exception):
def __init__(self, num):
print(f"NoPoolBreaker3 Constructor with num={num}")
self.num = num
def get_result(job):
exc = job.exception()
if type(exc) is PoolBreaker:
print("PoolBreaker", exc.num)
elif type(exc) is NoPoolBreaker1:
print("NoPoolBreaker1", exc.num)
elif type(exc) is NoPoolBreaker2:
print("NoPoolBreaker2", exc.num)
elif type(exc) is NoPoolBreaker3:
print("NoPoolBreaker3", exc.num)
else:
print(f"Exception: {str(exc)}")
def work(x: int):
if x == 0:
raise PoolBreaker(x)
elif x == 1:
raise NoPoolBreaker1(x)
elif x == 2:
raise NoPoolBreaker2(x)
elif x == 3:
raise NoPoolBreaker3(x)
if __name__ == '__main__':
for num in range(0, 4):
with ProcessPoolExecutor() as executor:
job = executor.submit(work, num)
get_result(job)
及其输出(python 3.7.3):
PoolBreaker Constructor with num=0
Exception: A process in the process pool was terminated abruptly while the future was running or pending.
NoPoolBreaker1 Constructor with num=1
NoPoolBreaker1 Constructor with num=-9
NoPoolBreaker1 1
NoPoolBreaker2 Constructor with num=2
NoPoolBreaker2 Constructor with num=2
NoPoolBreaker2 2
NoPoolBreaker3 Constructor with num=3
NoPoolBreaker3 Constructor with num=3
NoPoolBreaker3 3
如您所见,异常的构造函数被调用了两次,但让我们仔细研究一下这些情况:
TypeError: __init__() missing 1 required positional argument: 'num'
num
属性。因此,构造函数的第二次调用会收到具有正确值的必需num
属性,因此它可以正常工作。num
属性。因此,构造函数的第二次调用会收到具有正确值的必需num
属性,因此它可以正常工作。实际返回的Exception总是第一个,似乎第二个被丢弃了。
要在进程之间传输对象,必须对它们进行腌制和复制,这由ProcessPoolExecutor完成。 可能是第二次创建异常的原因。
当然,这不是解决问题的方法,可惜我还没有找到任何人。
我同时认为,这可能是库中的错误,因为:
请注意:我目前遇到的问题是,在某些程序中,NoPoolBreaker3不再起作用,并且还会导致“突然终止”异常。我不知道为什么,但这可能意味着行为取决于MWE中显示的更多内容。
答案 1 :(得分:0)
过去/现在是python泡菜中的错误,更多详细信息请参见:https://bugs.python.org/issue37208