2010-09-08 14 views
26

मेरे पास एक काफी जटिल पायथन ऑब्जेक्ट है जिसे मुझे कई प्रक्रियाओं के बीच साझा करने की आवश्यकता है। मैं multiprocessing.Process का उपयोग करके इन प्रक्रियाओं को लॉन्च करता हूं। जब मैं multiprocessing.Queue और multiprocessing.Pipe के साथ ऑब्जेक्ट साझा करता हूं, तो उन्हें ठीक से साझा किया जाता है। लेकिन जब मैं किसी ऑब्जेक्ट को अन्य गैर-मल्टीप्रोसेसिंग-मॉड्यूल ऑब्जेक्ट्स के साथ साझा करने का प्रयास करता हूं, तो ऐसा लगता है कि पाइथन इन ऑब्जेक्ट्स को फोर्क करता है। क्या यह सच है?पायथन प्रक्रियाओं के बीच एक जटिल वस्तु साझा करना?

मैंने multiprocessing.Value का उपयोग करने का प्रयास किया। लेकिन मुझे यकीन नहीं है कि किस प्रकार का होना चाहिए? मेरी ऑब्जेक्ट क्लास को MyClass कहा जाता है।

TypeError: this type has no size

किसी भी विचार क्या हो रहा है: लेकिन जब मैं multiprocess.Value(MyClass, instance) कोशिश, इसके साथ विफल रहता है?

+1

संबंधित: http://stackoverflow.com/questions/659865/python-multiprocessing-sharing-a-large-read-only-object-between-processes – tokland

उत्तर

23

आप इसे पाइथन के मल्टीप्रोसेसिंग "प्रबंधक" कक्षाओं और एक प्रॉक्सी क्लास का उपयोग करके कर सकते हैं जिसे आप परिभाषित करते हैं। अजगर डॉक्स से: http://docs.python.org/library/multiprocessing.html#proxy-objects

क्या आप क्या करना चाहते अपने कस्टम वस्तु के लिए एक प्रॉक्सी वर्ग को परिभाषित, और फिर एक "दूरस्थ प्रबंधक" का उपयोग कर वस्तु का हिस्सा है - के लिए एक ही जुड़ा हुआ डॉक पेज में उदाहरणों पर गौर "रिमोट मैनेजर" जहां दस्तावेज़ दिखाते हैं कि रिमोट कतार कैसे साझा करें। आप एक ही काम करने जा रहे हैं, लेकिन your_manager_instance.register() पर आपकी कॉल में आपकी कस्टम प्रॉक्सी क्लास अपनी तर्क सूची में शामिल होगी।

इस तरह, आप एक कस्टम प्रॉक्सी के साथ कस्टम ऑब्जेक्ट साझा करने के लिए एक सर्वर स्थापित कर रहे हैं। आपके क्लाइंट को सर्वर तक पहुंच की आवश्यकता है (फिर, रिमोट कतार में क्लाइंट/सर्वर एक्सेस को सेटअप करने के उत्कृष्ट दस्तावेज उदाहरण देखें, लेकिन कतार साझा करने के बजाय, आप अपनी विशिष्ट कक्षा तक पहुंच साझा कर रहे हैं)।

+3

इस प्रश्न में दिए गए कोड ने मेरे लिए दस्तावेज़ पृष्ठ को पूरक बनाने में मदद की। यह एक कस्टम वर्ग के साथ एक उदाहरण है। http://stackoverflow.com/questions/11951750/sharing-object-class-instance-in-python-using-managers – EarlCrapstone

15

बहुत सारे शोध और परीक्षण के बाद, मैंने पाया कि "प्रबंधक" गैर-जटिल ऑब्जेक्ट स्तर में यह कार्य करता है।

नीचे दिया गया कोड दिखाता है कि ऑब्जेक्ट inst प्रक्रियाओं के बीच साझा किया गया है, जिसका अर्थ है inst जब बच्चे की प्रक्रिया में परिवर्तन होता है तो बाहर बदल दिया जाता है।

from multiprocessing import Process, Manager 
from multiprocessing.managers import BaseManager 

class SimpleClass(object): 
    def __init__(self): 
     self.var = 0 

    def set(self, value): 
     self.var = value 

    def get(self): 
     return self.var 


def change_obj_value(obj): 
    obj.set(100) 


if __name__ == '__main__': 
    BaseManager.register('SimpleClass', SimpleClass) 
    manager = BaseManager() 
    manager.start() 
    inst = manager.SimpleClass() 

    p = Process(target=change_obj_value, args=[inst]) 
    p.start() 
    p.join() 

    print inst     # <__main__.SimpleClass object at 0x10cf82350> 
    print inst.get()    # 100 

ठीक है, इसके बाद के संस्करण कोड पर्याप्त अगर आप केवल सरल वस्तुओं साझा करने की आवश्यकता है।

कोई जटिल क्यों नहीं? क्योंकि यह विफल हो सकता है अगर आपके वस्तु (ऑब्जेक्ट के अंदर वस्तु) नीडिंत है:

from multiprocessing import Process, Manager 
from multiprocessing.managers import BaseManager 

class GetSetter(object): 
    def __init__(self): 
     self.var = None 

    def set(self, value): 
     self.var = value 

    def get(self): 
     return self.var 


class ChildClass(GetSetter): 
    pass 

class ParentClass(GetSetter): 
    def __init__(self): 
     self.child = ChildClass() 
     GetSetter.__init__(self) 

    def getChild(self): 
     return self.child 


def change_obj_value(obj): 
    obj.set(100) 
    obj.getChild().set(100) 


if __name__ == '__main__': 
    BaseManager.register('ParentClass', ParentClass) 
    manager = BaseManager() 
    manager.start() 
    inst2 = manager.ParentClass() 

    p2 = Process(target=change_obj_value, args=[inst2]) 
    p2.start() 
    p2.join() 

    print inst2     # <__main__.ParentClass object at 0x10cf82350> 
    print inst2.getChild()   # <__main__.ChildClass object at 0x10cf6dc50> 
    print inst2.get()    # 100 
    #good! 

    print inst2.getChild().get() # None 
    #bad! you need to register child class too but there's almost no way to do it 
    #even if you did register child class, you may get PicklingError :) 

मुझे लगता है कि क्योंकि Manager सिर्फ एक candybar पाइप की तरह निम्न स्तर के संचार उपकरण के शीर्ष पर निर्माण है इस व्यवहार का मुख्य कारण यह है /कतार।

तो, यह दृष्टिकोण मल्टीप्रोसेसिंग मामले के लिए अच्छी तरह से अनुशंसित नहीं है। यह हमेशा बेहतर है अगर आप की तरह Redis कतार या Redis या उच्च स्तर के उपकरण की तरह लॉक/सेमाफोर/पाइप/कतार निम्न स्तर के उपकरणों का उपयोग कर सकते हैं प्रकाशित/जटिल उपयोग के मामले (केवल मेरी सिफारिश lol) के लिए सदस्यता ले रहा है।

+0

जटिल वस्तु को कैसे साझा करें? –

0

साझा संसाधनों के साथ कुछ सिरदर्द बचाने के लिए आप डेटा एकत्र करने का प्रयास कर सकते हैं जिसके लिए मैप किए गए फ़ंक्शन के रिटर्न स्टेटमेंट में सिंगलटन संसाधन तक पहुंच की आवश्यकता है।pool.imap_unordered और फिर आगे एक पाश है कि आंशिक परिणामों को पुन: प्राप्त करने में इसे संसाधित:

for result in in pool.imap_unordered(process_function, iterable_data): 
    do_something(result) 

यदि यह अधिक डेटा है कि वापस आ जाता है नहीं है, तो वहाँ ऐसा करने में ज्यादा भूमि के ऊपर नहीं हो सकता है।

2

यहां केवल एक पायथन पैकेज है जो मैंने इसके लिए बनाया है (प्रक्रियाओं के बीच जटिल वस्तुओं को साझा करना)।

Git: https://github.com/dRoje/pipe-proxy

विचार आप अपनी वस्तु के लिए एक प्रॉक्सी बना सकते हैं और यह एक प्रक्रिया के पास है। फिर आप प्रॉक्सी का उपयोग करते हैं जैसे कि आपके पास मूल ऑब्जेक्ट का संदर्भ है। यद्यपि आप केवल विधि कॉल का उपयोग कर सकते हैं, इसलिए ऑब्जेक्ट चरों तक पहुंचने से सेटर्स और गेटर्स फेंक दिए जाते हैं।

कहते हैं कि हम एक वस्तु 'उदाहरण' कहा जाता है, प्रॉक्सी और प्रॉक्सी श्रोता बनाने आसान है:

from pipeproxy import proxy 
example = Example() 
exampleProxy, exampleProxyListener = proxy.createProxy(example) 

अब आप किसी अन्य प्रक्रिया के लिए प्रॉक्सी भेजें।

p = Process(target=someMethod, args=(exampleProxy,)) p.start() 

अन्य प्रक्रिया में इसका इस्तेमाल के रूप में आप मूल वस्तु (उदाहरण) का प्रयोग करेंगे:

def someMethod(exampleProxy): 
    ... 
    exampleProxy.originalExampleMethod() 
    ... 

लेकिन आप मुख्य प्रक्रिया में यह सुनने के लिए क्या है:

exampleProxyListener.listen() 

और पढ़ें और यहां उदाहरण खोजें:

http://matkodjipalo.com/index.php/2017/11/12/proxy-solution-python-multiprocessing/

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