Python decorator с многопроцессорной обработкой терпит неудачу
Я хотел бы использовать декоратор для функции, которую я впоследствии передам в многопроцессорный пул. Однако код завершается с ошибкой "PicklingError: Can't pickle: attribute lookup __builtin__.сбой функции". Я не совсем понимаю, почему это не удается здесь. Я уверен, что это что-то простое, но я не могу найти его. Ниже приведен минимальный "рабочий" пример. Я думал, что использование функции functools будет достаточно, чтобы это сработало.
Если я закомментирую украшение функции, оно работает без вопрос. Что это за multiprocessing, что я здесь не понимаю? Есть ли какой-нибудь способ заставить это работать?
Edit : после добавления как вызываемого класса decorator , так и функции decorator, оказывается, что функция decorator работает так, как ожидалось. Вызываемый декоратор класса продолжает давать сбои. Что такого есть в вызываемой версии класса, что удерживает ее от маринования?
import random
import multiprocessing
import functools
class my_decorator_class(object):
def __init__(self, target):
self.target = target
try:
functools.update_wrapper(self, target)
except:
pass
def __call__(self, elements):
f = []
for element in elements:
f.append(self.target([element])[0])
return f
def my_decorator_function(target):
@functools.wraps(target)
def inner(elements):
f = []
for element in elements:
f.append(target([element])[0])
return f
return inner
@my_decorator_function
def my_func(elements):
f = []
for element in elements:
f.append(sum(element))
return f
if __name__ == '__main__':
elements = [[random.randint(0, 9) for _ in range(5)] for _ in range(10)]
pool = multiprocessing.Pool(processes=4)
results = [pool.apply_async(my_func, ([e],)) for e in elements]
pool.close()
f = [r.get()[0] for r in results]
print(f)
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.цель
Это не очень хорошо. Это функция на высшем уровне, и обычно их можно замариновать. Рассол будет хранить имя функции. Проблема, однако, в том, что имя "my_func" больше не привязано к неотмеченной функции, это привязка к оформленной функции. Это означает, что Пикл не сможет найти функцию undecorated, чтобы воссоздать объект. К сожалению, pickle не имеет никакого способа узнать, что объект, который он пытается замариновать, всегда можно найти под именем 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изменяет украшенный функция так, чтобы она имела имя и другие свойства функции, которую она обертывает. Насколько модуль маринования может сказать, он неотличим от обычной функции верхнего уровня, поэтому он маринует его, сохраняя его имя. После распаковки имя привязывается к оформленной функции, поэтому все работает.
Comments