给定此示例场景:
def _callback(result):
if result == 2:
# introduce an exception into one of the callbacks
raise Exception("foo")
print (result)
def _target(v):
return v
worker_pool = Pool()
for i in range(10):
worker_pool.apply_async(_target, args=(i,), callback=_callback)
worker_pool.close()
worker_pool.join()
我希望看到除了i=2
之外的i
的每个值都被打印出来,这会产生一个异常。
相反,我看到了以下内容:
0
1
Exception in thread Thread-3:
Traceback (most recent call last):
File "/usr/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/usr/lib/python3.6/multiprocessing/pool.py", line 479, in _handle_results
cache[job]._set(i, obj)
File "/usr/lib/python3.6/multiprocessing/pool.py", line 649, in _set
self._callback(self._value)
File "test3.py", line 6, in _callback
raise Exception("foo")
Exception: foo
然后执行就挂起了。
我知道Pool
在一个单独的线程上处理回调,但为什么执行会挂起,以及如何可靠地防止任务回调中的错误?
之所以会发生这种情况,是因为回调方法内部的异常基本上会杀死处理Pool
的线程,因为它没有except
块来处理这种情况。在Thread
死后,它无法join
和worker_pool
,因此您的应用程序挂起。
我相信这是Python维护人员做出的决定,所以处理这个异常的最好方法是将代码封装在try/except块中并进行处理,而不是冒泡并杀死线程。