Пул должен выбрать (сериализовать) все, что он посылает своим рабочим процессам.Активирование на самом деле сохраняет только имя функции, а для восстановления требуется повторный импорт функции по имени.Чтобы это работало, функция должна быть определена на верхнем уровне, вложенные функции не будут импортироваться дочерним элементом, и уже при попытке их выбора возникает исключение:
from multiprocessing.connection import _ForkingPickler
def run():
def foo(x):
pass
_ForkingPickler.dumps(foo) # multiprocessing custom pickler;
# same effect with pickle.dumps(foo)
run()
# Out:
Traceback (most recent call last):
...
AttributeError: Can't pickle local object 'run.<locals>.foo'
Причина, по которой выне вижу исключений, потому что Pool
уже начинает перехватывать исключения во время задач выбора в родительском объекте и только повторно вызывает их, когда вы вызываете .get()
для объекта AsyncResult
, который вы сразу получаете, когда вызываете pool.apply_async()
.
Вот почему (с Python 2) вам лучше всегда использовать его так, даже если ваша целевая функция ничего не возвращает (по-прежнему возвращает неявное None
):
results = [pool.apply_async(foo, (i,)) for i in range(4)]
# `pool.apply_async()` immediately returns AsyncResult (ApplyResult) object
for res in results:
res.get()
В Python 3 есть error_callback
-параметр для асинхронных методов пула, который вы можете использовать вместо этого для обработки исключений.