Многопроцессорные объекты с namedtuple — ошибка травления

У меня возникли проблемы с использованием namedtuples в объектах, которые я хочу поместить в многопроцессорную обработку. Я получаю ошибку травления. Я попробовал пару вещей из других сообщений stackoverflow, но у меня не получилось. Вот структура моего кода:

пакет_основной, тестовый_модуль

 import myprogram.package_of_classes.data_object_module
 import ....obj_calculate

 class test(object):
       if __name__ == '__main__':
             my_obj=create_obj('myobject',['f1','f2'])
             input = multiprocessing.Queue()
             output = multiprocessing.Queue()
             input.put(my_obj)
             j=Process(target=obj_calculate, args=(input,output))
             j.start()

package_of_classes, data_object_module

 import collections
 import ....load_flat_file

 def get_ntuple_format(obj):
     nt_fields=''
     for fld in obj.fields:
         nt_fields=nt_fields+fld+', '
     nt_fields=nt_fields[0:-2]
     ntuple=collections.namedtuple('ntuple_format',nt_fields)
     return ntuple

 Class Data_obj:
    def __init__(self, name,fields):
        self.name=name
        self.fields=fields
        self.ntuple_form=get_ntuple_format(self)  

    def calculate(self):
        self.file_read('C:/files','division.txt')

    def file_read(self,data_directory,filename):
        output=load_flat_file(data_directory,filename,self.ntuple_form)
        self.data=output

utils_package, utils_module

def create_dataobj(name,fields):
    locals()[name]=Data_Obj(name,fields)
    return locals()[name]  

def obj_calculate(input,output):   
    obj=input.get()
    obj.calculate()
    output.put(obj)

load_module

def load_flat_file(data_directory,filename,ntuple_form):
     csv.register_dialect('csvrd', delimiter='\t', quoting=csv.QUOTE_NONE)
     ListofTuples=[]
     with open(os.path.join(data_directory,filename), 'rb') as f:
          reader = csv.reader(f,'csvrd')
          for line in reader:
               if line:
                   ListofTuples.append(ntuple_form._make(line))
     return ListofTuples

И ошибка, которую я получаю:

PicklingError: PicklingError: Can't pickle  class '__main__ . ntuple_format: it's not the same object as __ main __. ntuple_format

P.S. Поскольку я извлек этот пример кода из большого проекта, не обращайте внимания на мелкие несоответствия.


person Enes    schedule 10.03.2014    source источник
comment
Можете ли вы предоставить полную трассировку? Вы выполняете это в Windows? Есть ли у вас возможность выполнить его в Linux (способ предоставления данных дочернему процессу полностью отличается в обеих системах, в Linux травление может быть пропущено)?   -  person Dr. Jan-Philip Gehrcke    schedule 10.03.2014
comment
укажите SSCCE для своей проблемы, чтобы вы могли извлечь проблемную часть из остальной части код вашего проекта, который затрудняет понимание того, какие типы задействованы, где они объявлены, какова продолжительность жизни процессов и т. д. Пожалуйста, помогите нам помочь вам!   -  person zmo    schedule 10.03.2014


Ответы (2)


Вы не можете выбрать класс (в данном случае именованный кортеж), который вы создаете динамически (через get_ntuple_format). Чтобы класс можно было выбрать, у него должен быть определен на верхнем уровне импортируемого модуля.

Если у вас есть только несколько типов кортежей, которые вам нужно поддерживать, подумайте о том, чтобы определить их все заранее, на верхнем уровне модуля, а затем выбрать правильный динамически. Если вам нужен полностью динамический формат контейнера, рассмотрите возможность использования вместо него dict.

person Vasiliy Faronov    schedule 10.03.2014

Я бы сказал, что вы можете замариновать namedtuple, а также class, определенный в __main__.

>>> import dill as pickle
>>> import collections
>>> 
>>> thing = collections.namedtuple('thing', ['a','b'])
>>> pickle.loads(pickle.dumps(thing))
<class '__main__.thing'>

Вот то же самое, используемое в методе класса.

>>> class Foo(object):
...   def bar(self, a, b):
...     thing = collections.namedtuple('thing', ['a','b'])     
...     thing.a = a 
...     thing.b = b
...     return thing 
... 
>>> f = Foo()
>>> q = f.bar(1,2)
>>> q.a
1
>>> q.b
2
>>> q._fields
('a', 'b')
>>> 
>>> pickle.loads(pickle.dumps(Foo.bar))
<unbound method Foo.bar>
>>> pickle.loads(pickle.dumps(f.bar))
<bound method Foo.bar of <__main__.Foo object at 0x10dbf5450>>

Вам просто нужно использовать dill вместо pickle.

Получите dill здесь: https://github.com/uqfoundation

person Mike McKerns    schedule 13.04.2014