2012-02-24 18 views
37

मैं multiprocessing.Manager() अजगर में के बारे में एक चिंता का विषय यहाँ उदाहरण हैmultiprocessing.Manager() पायथन में कैसे काम करता है?

import multiprocessing 

def f(ns): 

    ns.x *=10 
    ns.y *= 10 

if __name__ == '__main__': 
    manager = multiprocessing.Manager() 
    ns = manager.Namespace() 
    ns.x = 1 
    ns.y = 2 

    print 'before', ns 
    p = multiprocessing.Process(target=f, args=(ns,)) 
    p.start() 
    p.join() 
    print 'after', ns 

है, और उत्पादन है,

before Namespace(x=1, y=2) 
after Namespace(x=10, y=20) 

अब तक, यह मेरी अपेक्षा के अनुरूप काम किया, तो मैं इस तरह कोड,

import multiprocessing 

def f(ns): 

    ns.x.append(10) 
    ns.y.append(10) 

if __name__ == '__main__': 
    manager = multiprocessing.Manager() 
    ns = manager.Namespace() 
    ns.x = [] 
    ns.y = [] 

    print 'before', ns 
    p = multiprocessing.Process(target=f, args=(ns,)) 
    p.start() 
    p.join() 
    print 'after', ns 
अब

संशोधित, उत्पादन होता है,

before Namespace(x=[], y=[]) 
after Namespace(x=[], y=[]) 

यह मुझे भ्रमित कर दिया गया कि मेरी अपेक्षा के अनुसार सूची क्यों नहीं बदला गया था? क्या हुआ यह जानने में कोई मेरी मदद कर सकता है? अग्रिम में धन्यवाद!

उत्तर

40

नोट: यह उत्तर पायथन 3.6+ के लिए सटीक हो सकता है या नहीं भी हो सकता है। नीचे दी गई टिप्पणियां देखें, जो विरोधाभासी चीजों को इंगित करती हैं। जब मैं जांच करने के लिए कुछ समय निकालूं तो मैं अपडेट करूंगा। (यदि आप जानते हैं क्या हो रहा है इस जवाब को संपादित करने के लिए स्वतंत्र महसूस!)


प्रबंधक प्रॉक्सी वस्तुओं एक कंटेनर के अंदर परिवर्तनशील वस्तुओं में किए गए परिवर्तनों का प्रचार करने में असमर्थ हैं। तो दूसरे शब्दों में, यदि आपके पास manager.list() ऑब्जेक्ट है, तो प्रबंधित सूची में किए गए किसी भी बदलाव को अन्य सभी प्रक्रियाओं के लिए प्रचारित किया जाता है। लेकिन अगर आपके पास की सूची है, तो सूची में, आंतरिक सूची में किए गए किसी भी बदलाव को प्रचारित नहीं किया जाता है, क्योंकि प्रबंधक के पास परिवर्तन का पता लगाने का कोई तरीका नहीं है।

परिवर्तनों को प्रसारित करने के लिए, आपको here नोट द्वारा संकेतित अनुसार manager.list() ऑब्जेक्ट को सीधे संशोधित करना होगा।

import multiprocessing 
import time 

def f(ns, ls, di): 
    ns.x += 1 
    ns.y[0] += 1 
    ns_z = ns.z 
    ns_z[0] += 1 
    ns.z = ns_z 

    ls[0] += 1 
    ls[1][0] += 1 
    ls_2 = ls[2] 
    ls_2[0] += 1 
    ls[2] = ls_2 

    di[0] += 1 
    di[1][0] += 1 
    di_2 = di[2] 
    di_2[0] += 1 
    di[2] = di_2 

if __name__ == '__main__': 
    manager = multiprocessing.Manager() 
    ns = manager.Namespace() 
    ns.x = 1 
    ns.y = [1] 
    ns.z = [1] 
    ls = manager.list([1, [1], [1]]) 
    di = manager.dict({0: 1, 1: [1], 2:[1]}) 

    print 'before', ns, ls, di 
    p = multiprocessing.Process(target=f, args=(ns, ls, di)) 
    p.start() 
    p.join() 
    print 'after', ns, ls, di 

आउटपुट::

before Namespace(x=1, y=[1], z=[1]) [1, [1], [1]] {0: 1, 1: [1], 2: [1]} 
after Namespace(x=2, y=[1], z=[2]) [2, [1], [2]] {0: 2, 1: [1], 2: [2]} 

आप देख सकते हैं, जब एक नया मूल्य में कामयाब रहे कंटेनर के लिए सीधे असाइन किया गया है, यह परिवर्तन

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

+3

3.6 से शुरू होने से, नेस्टेड ऑब्जेक्ट्स में परिवर्तन स्वचालित रूप से प्रचारित होते हैं। – max

+0

मैंने पाइथन 3.6.4 पर प्रबंधक के साथ नेमस्पेस के भीतर नेस्टेड शब्दकोशों का उपयोग करके कुछ मुद्दों में भाग लिया है। सुनिश्चित करें कि आगे बढ़ने से पहले आपके नेस्टेड ऑब्जेक्ट्स को ठीक से अपडेट किया जा रहा है। मेरे लिए समाधान स्पष्ट रूप से प्रत्येक ऑब्जेक्ट को प्रबंधक ऑब्जेक्ट के रूप में साझा करने के लिए परिभाषित करना था। – Joules

16

ns एक NamespaceProxy उदाहरण है। इन वस्तुओं में विशेष __getattr__, __setattr__, और __delattr__ विधियां हैं जो प्रक्रियाओं में मानों को साझा करने की अनुमति देती हैं। कोई मान बदलने पर इस तंत्र का लाभ उठाने के लिए, आपको __setattr__ ट्रिगर करना होगा।

ns.x.append(10) 

ns.__getattr__ का कारण बनता है ns.x को पुनः प्राप्त करने के नाम से जाना है, लेकिन यह कारण नहीं है ns.__setattr__ कहा जाता है।

इसे ठीक करने के लिए आपको ns.x = ... उपयोग करना चाहिए।

def f(ns): 
    tmp = ns.x  # retrieve the shared value 
    tmp.append(10) 
    ns.x = tmp  # set the shared value 
संबंधित मुद्दे