2012-02-17 30 views
13

मैं एक समारोह पर एक सजावट का उपयोग करना चाहता हूं जिसे मैं बाद में एक मल्टीप्रोसेसिंग पूल में भेज दूंगा। हालांकि, कोड "पिकलिंग एरर: अचार नहीं कर सकता: विशेषता लुकअप __builtin__। विफल विफल" के साथ विफल रहता है। मुझे नहीं लगता कि यह यहां क्यों विफल रहता है। मुझे यकीन है कि यह कुछ आसान है, लेकिन मुझे यह नहीं मिल रहा है। नीचे एक न्यूनतम "कामकाजी" उदाहरण है। मैंने सोचा कि functools फ़ंक्शन का उपयोग इस काम को करने के लिए पर्याप्त होगा।मल्टीप्रोसेसिंग के साथ पाइथन सजावट

यदि मैं फ़ंक्शन सजावट पर टिप्पणी करता हूं, तो यह किसी समस्या के बिना काम करता है। multiprocessing के बारे में क्या है कि मैं यहां गलतफहमी कर रहा हूं? क्या यह काम करने का कोई तरीका है?

संपादित: दोनों एक प्रतिदेय वर्ग डेकोरेटर और एक समारोह डेकोरेटर जोड़ने के बाद, यह पता चला है कि समारोह डेकोरेटर अपेक्षा के अनुरूप काम करता है। कॉल करने योग्य वर्ग सजावट असफल रहा है। कॉल करने योग्य वर्ग संस्करण के बारे में क्या है जो इसे मसालेदार रखने से रोकता है?

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) 
+0

यह पोस्ट इंगित करता है कि पिकलिंग सजाए गए सामान मुश्किल हैं: http://gael-varoquaux.info/blog/?पी = 120 – Daenyth

+0

हां, मुझे वह पृष्ठ भी मिला। यही कारण है कि मैंने 'functools' रैपर जोड़ा। लेकिन ऐसा कोई फर्क नहीं पड़ता है। मैं कबूल करता हूं कि मैं वास्तव में यह नहीं समझता कि यह क्यों विफल हो रहा है यह देखने में नीचे क्या हो रहा है। – agarrett

उत्तर

8

समस्या यह है कि अचार को आपके द्वारा चुने गए सभी चीज़ों को फिर से इकट्ठा करने की आवश्यकता होती है। यहाँ क्या मसालेदार किया जा सकता है की एक सूची के लिए देखें:

  • my_decorator_class का एक उदाहरण, कहा जाता my_func

    :

    http://docs.python.org/library/pickle.html#what-can-be-pickled-and-unpickled

    जब my_func नमकीन बनाना, निम्न घटक मसालेदार होने की जरूरत है यह ठीक है। अचार कक्षा के नाम को स्टोर करेगा और __dict__ सामग्री उठाएगा। जब unpickling, यह वर्ग खोजने के लिए नाम का उपयोग करता है, तो एक उदाहरण बनाता है और __dict__ सामग्री में भरता है। हालांकि, __dict__ सामग्री एक समस्या पेश ...

  • मूल my_func का उदाहरण है कि my_func.target

    में संग्रह किया गया है यह बहुत अच्छा नहीं है। यह शीर्ष-स्तर पर एक कार्य है, और आमतौर पर इन्हें मसालेदार किया जा सकता है। अचार फ़ंक्शन का नाम संग्रहीत करेगा। हालांकि, समस्या यह है कि "my_func" नाम अब अवांछित फ़ंक्शन से बंधे नहीं है, यह सजाए गए फ़ंक्शन से जुड़ा हुआ है। इसका मतलब यह है कि अचार वस्तु को फिर से बनाने के लिए अवांछित फ़ंक्शन को देखने में सक्षम नहीं होगा। अफसोस की बात है कि, अचार को यह जानने का कोई तरीका नहीं है कि वह ऑब्जेक्ट को चुनने की कोशिश कर रहा है, हमेशा मुख्य .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 सजाए गए फ़ंक्शन को संशोधित करता है ताकि उसके नाम और फ़ंक्शन के अन्य गुण हों। जहां तक ​​अचार मॉड्यूल बता सकता है, यह सामान्य शीर्ष-स्तरीय फ़ंक्शन से अलग नहीं है, इसलिए यह इसका नाम संग्रहीत करके इसे चुनता है। अनपिकलिंग पर, नाम सजाए गए फ़ंक्शन से जुड़ा हुआ है, इसलिए सब कुछ काम करता है।

+0

ठीक है। तो अगर मैं इन चीजों को अचार करना चाहता हूं, और यदि मैं अपने सजावटी के रूप में एक कॉल करने योग्य वर्ग का उपयोग करना चाहता हूं, तो मैं '@' सजावट दृष्टिकोण का उपयोग नहीं कर पाऊंगा। मुझे इसका इस्तेमाल करना होगा जैसे कि मैं कक्षा को तुरंत चालू कर रहा था। क्या वो सही है? – agarrett

+0

मेरा मानना ​​है कि यह सही है। वैकल्पिक रूप से, आप एक छोटे से गैर-सजाए गए शीर्ष-स्तरीय फ़ंक्शन को बनाकर इसे पिकलिंग से बच सकते हैं जो केवल सजाए गए फ़ंक्शन के लिए आगे बढ़ता है। – Weeble

+0

बहुत स्पष्ट। बहुत बहुत धन्यवाद। – agarrett

संबंधित मुद्दे