Python: (Пафос) Многопроцессорность против методов класса

Я пытаюсь распараллелить код, используя методы класса с помощью многопроцессорности. Базовая структура следующая:

# from multiprocessing import Pool
from pathos.multiprocessing import ProcessingPool as Pool

class myclass(object):
    def __init__(self):
        #some code
    def mymethod(self):
        #more code
        return another_instance_of_myclass



def myfunc(myinstance,args):
    #some code   
    test=myinstance.mymethod()
    #more code
    return myresult #not an instance,just a number

p=Pool()

result = p.map(myfunc,listwithdata)

После того, как это не удалось с обычной многопроцессорной обработкой, я узнал о проблемах с Pickle и многопроцессорной обработкой, поэтому я попытался решить ее с помощью multiprocessing.pathos. Тем не менее, я все еще получаю

PicklingError: Can't pickle <type 'SwigPyObject'>: it's not found as__builtin__.SwigPyObjec

вместе с множеством ошибок от pickle.py. Помимо этой практической проблемы, я не совсем понимаю, почему что-то, кроме конечного результата myfunc, вообще маринуется.


person user4319496    schedule 18.03.2015    source источник
comment
Похоже, что dill не работает со Swig из коробки. См. этот вопрос, в котором есть решение для делая объекты Swig доступными для обработки. Возможно, вы сможете использовать его.   -  person dano    schedule 18.03.2015
comment
Должен признаться, мне даже потребовалось некоторое время, чтобы выяснить, откуда берется объект SwigPy (сам я его не определял). Оказывается, один из модулей, которые я использую, в свою очередь использует числовые библиотеки, написанные на C. Копаться во всем этом выглядит сложно, но я попробую.   -  person user4319496    schedule 19.03.2015


Ответы (2)


pathos использует dill, а dill сериализует классы иначе, чем модуль pickle Python. pickle сериализует классы по ссылке. dill (по умолчанию) сериализует классы напрямую и только опционально по ссылке.

>>> import dill
>>> 
>>> class Foo(object):
...   def __init__(self, x):
...     self.x = x
...   def bar(self, y):
...     return self.x + y * z
...   z = 1
... 
>>> f = Foo(2)
>>> 
>>> dill.dumps(f)  # the dill default, explicitly serialize a class
'\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x03Fooq\x05h\x01U\nObjectTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\r__slotnames__q\x0b]q\x0cU\n__module__q\rU\x08__main__q\x0eU\x03barq\x0fcdill.dill\n_create_function\nq\x10(cdill.dill\n_unmarshal\nq\x11Uyc\x02\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00C\x00\x00\x00s\x0f\x00\x00\x00|\x00\x00j\x00\x00|\x01\x00t\x01\x00\x14\x17S(\x01\x00\x00\x00N(\x02\x00\x00\x00t\x01\x00\x00\x00xt\x01\x00\x00\x00z(\x02\x00\x00\x00t\x04\x00\x00\x00selft\x01\x00\x00\x00y(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x03\x00\x00\x00bar\x04\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x12\x85q\x13Rq\x14c__builtin__\n__main__\nh\x0fNN}q\x15tq\x16Rq\x17U\x01zq\x18K\x01U\x07__doc__q\x19NU\x08__init__q\x1ah\x10(h\x11Uuc\x02\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s\r\x00\x00\x00|\x01\x00|\x00\x00_\x00\x00d\x00\x00S(\x01\x00\x00\x00N(\x01\x00\x00\x00t\x01\x00\x00\x00x(\x02\x00\x00\x00t\x04\x00\x00\x00selfR\x00\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x08\x00\x00\x00__init__\x02\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x1b\x85q\x1cRq\x1dc__builtin__\n__main__\nh\x1aNN}q\x1etq\x1fRq utq!Rq")\x81q#}q$U\x01xq%K\x02sb.'
>>> dill.dumps(f, byref=True)  # the pickle default, serialize by reference
'\x80\x02c__main__\nFoo\nq\x00)\x81q\x01}q\x02U\x01xq\x03K\x02sb.'

Отсутствие сериализации по ссылке гораздо более гибко. Однако в редких случаях лучше работать со ссылками (как это происходит при травлении чего-то, построенного на SwigPyObject).

Я имел в виду (в течение ~ 2 лет) выставить флаг byref для вызова dump внутри pathos, но еще не сделал этого. Это должно быть довольно простое редактирование, чтобы сделать это. Я только что добавил для этого тикет: https://github.com/uqfoundation/pathos/issues/58. Пока я занимаюсь этим, также должно быть легко открыть замену функций dump и load, которые использует pathos… таким образом, вы можете использовать настраиваемые сериализаторы (т.е. расширять те, которые предоставляет dill, или использовать какой-либо другой сериализатор).

person Mike McKerns    schedule 18.03.2015
comment
Здорово! Буду регулярно проверять ваш билет и, конечно же, пробовать его, как только редактирование будет завершено. - person user4319496; 19.03.2015

В многопроцессорной функции сериализация необходима для межпроцессного взаимодействия. Pickle плохо справляется с этой задачей, вместо этого установите dill через pip. Подробности (с хорошим примером из «Звездного пути») можно найти здесь: http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization/

person barrios    schedule 18.03.2015
comment
Спасибо за ссылку. По крайней мере, на примере «Звездного пути» я понимаю, почему методы должны быть маринованными. Но в приведенном выше примере я уже использую pathos.multiprocessing, и все равно ничего не получается. - person user4319496; 18.03.2015
comment
@barrios: я автор pathos и dill. ОП правильный. pathos использует dill из коробки. - person Mike McKerns; 18.03.2015
comment
извините, не знал этого. - person barrios; 19.03.2015