Ответ 1
Проблема в том, что маринование должно иметь какой-то способ собрать все, что вы соберете. См. Здесь список того, что можно мариновать:
http://docs.python.org/library/pickle.html#what-can-be-pickled-and-unpickled
При травлении my_func необходимо смазать следующие компоненты:
-
Экземпляр класса my_decorator_class, называемый my_func
Это нормально. Pickle сохранит имя класса и рассортирует его содержимое
__dict__
. При рассыпании он использует имя для поиска класса, затем создает экземпляр и заполняет содержимое__dict__
. Однако содержимое__dict__
представляет проблему... -
Экземпляр исходного my_func, который хранится в my_func.target
Это не так хорошо. Это функция на верхнем уровне, и обычно их можно мариновать. Pickle сохранит имя функции. Проблема, однако, в том, что имя "my_func" больше не привязано к неразделенной функции, оно связано с украшенной функцией. Это означает, что рассол не сможет найти неубранную функцию для воссоздания объекта. К сожалению, маринование не имеет никакого способа узнать, что объект, который он пытается рассолить, всегда можно найти под названием main.my_func.
Вы можете изменить его так и он будет работать:
import random
import multiprocessing
import functools
class my_decorator(object):
def __init__(self, target):
self.target = target
try:
functools.update_wrapper(self, target)
except:
pass
def __call__(self, candidates, args):
f = []
for candidate in candidates:
f.append(self.target([candidate], args)[0])
return f
def old_my_func(candidates, args):
f = []
for c in candidates:
f.append(sum(c))
return f
my_func = my_decorator(old_my_func)
if __name__ == '__main__':
candidates = [[random.randint(0, 9) for _ in range(5)] for _ in range(10)]
pool = multiprocessing.Pool(processes=4)
results = [pool.apply_async(my_func, ([c], {})) for c in candidates]
pool.close()
f = [r.get()[0] for r in results]
print(f)
Вы заметили, что функция декоратора работает, когда класс не работает. Я считаю, что это потому, что functools.wraps
изменяет украшенную функцию так, что она имеет имя и другие свойства функции, которую она обертывает. Поскольку модуль рассола может сказать, он неотличим от нормальной функции верхнего уровня, поэтому он замачивает его, сохраняя его имя. После рассыпания имя привязано к украшенной функции, поэтому все работает.