2015-02-19 13 views
9

मैं वैश्विक ऑब्जेक्ट रखना चाहता हूं जो न्यूनतम प्रक्रियाओं के साथ सभी प्रक्रियाओं द्वारा साझा और अद्यतन किया जाता है।मैं प्रक्रियाओं के बीच कक्षा कैसे साझा कर सकता हूं?

import multiprocessing 

class Counter(object): 
    def __init__(self): 
    self.value = 0 

    def update(self, value): 
    self.value += value 


def update(counter_proxy, thread_id): 
    counter_proxy.value.update(1) 
    print counter_proxy.value.value, 't%s' % thread_id, \ 
    multiprocessing.current_process().name 
    return counter_proxy.value.value 

def main(): 
    manager = multiprocessing.Manager() 
    counter = manager.Value(Counter, Counter()) 
    pool = multiprocessing.Pool(multiprocessing.cpu_count()) 
    for i in range(10): 
    pool.apply(func = update, args = (counter, i)) 
    pool.close() 
    pool.join() 

    print 'Should be 10 but is %s.' % counter.value.value 

if __name__ == '__main__': 
    main() 

परिणाम यह है - 10 नहीं बल्कि शून्य। ऐसा लगता है कि ऑब्जेक्ट का साझा मूल्य अपडेट नहीं किया गया है। मैं इस तरह के मूल्य को कैसे लॉक और अपडेट कर सकता हूं?

0 t0 PoolWorker-2 
0 t1 PoolWorker-3 
0 t2 PoolWorker-5 
0 t3 PoolWorker-8 
0 t4 PoolWorker-9 
0 t5 PoolWorker-2 
0 t6 PoolWorker-7 
0 t7 PoolWorker-4 
0 t8 PoolWorker-6 
0 t9 PoolWorker-3 
Should be 10 but is 0. 

वर्तमान @dano द्वारा सबसे अच्छा समाधान - मैं कक्षा प्रॉक्सी के साथ कस्टम प्रबंधक मिलाया।

import multiprocessing 
from multiprocessing.managers import BaseManager, NamespaceProxy 


class Counter(object): 
    def __init__(self): 
    self.value = 0 

    def update(self, value): 
    self.value += value 


def update(counter_proxy, thread_id): 
    counter_proxy.update(1) 

class CounterManager(BaseManager): 
    pass 

class CounterProxy(NamespaceProxy): 
    _exposed_ = ('__getattribute__', '__setattr__', '__delattr__', 'update') 

    def update(self, value): 
    callmethod = object.__getattribute__(self, '_callmethod') 
    return callmethod(self.update.__name__, (value,)) 

CounterManager.register('Counter', Counter, CounterProxy) 

def main(): 
    manager = CounterManager() 
    manager.start() 

    counter = manager.Counter() 
    pool = multiprocessing.Pool(multiprocessing.cpu_count()) 
    for i in range(10): 
    pool.apply(func = update, args = (counter, i)) 
    pool.close() 
    pool.join() 

    print 'Should be 10 but is %s.' % counter.value 

if __name__ == '__main__': 
    main() 
+0

आप 'NamespaceProxy' के बारे में कैसे सीखा? मुझे कहीं भी इसका दस्तावेज नहीं मिल रहा है। – Seanny123

उत्तर

10

multiprocessing.Value कस्टम वर्गों के साथ इस्तेमाल किया जा करने के लिए नहीं है, यह एक multiprocessing.sharedctypes.Value के समान होने की अपेक्षा की जाती है। इसके बजाय, आपको custom manager बनाने की आवश्यकता है और इसके साथ अपनी कक्षा पंजीकृत करें। यदि आप सीधे value तक पहुंच नहीं पाते हैं, लेकिन विधियों के माध्यम से इसे संशोधित/एक्सेस नहीं करते हैं, तो डिफ़ॉल्ट रूप से आपकी कक्षा के लिए बनाए गए डिफ़ॉल्ट Proxy द्वारा निर्यात किया जाएगा। नियमित गुण (जैसे Counter.value) नहीं हैं, इसलिए वे अतिरिक्त अनुकूलन के बिना पहुंच योग्य नहीं हैं। यहाँ एक काम कर उदाहरण है:

import multiprocessing 
from multiprocessing.managers import BaseManager 

class MyManager(BaseManager): pass 

def Manager(): 
    m = MyManager() 
    m.start() 
    return m 

class Counter(object): 
    def __init__(self): 
    self._value = 0 

    def update(self, value): 
    self._value += value 

    def get_value(self): 
     return self._value 

MyManager.register('Counter', Counter) 

def update(counter_proxy, thread_id): 
    counter_proxy.update(1) 
    print counter_proxy.get_value(), 't%s' % thread_id, \ 
    multiprocessing.current_process().name 
    return counter_proxy 

def main(): 
    manager = Manager() 
    counter = manager.Counter() 
    pool = multiprocessing.Pool(multiprocessing.cpu_count()) 
    for i in range(10): 
    pool.apply(func=update, args=(counter, i)) 
    pool.close() 
    pool.join() 

    print 'Should be 10 but is %s.' % counter.get_value() 

if __name__ == '__main__': 
    main() 

आउटपुट:

1 t0 PoolWorker-2 
2 t1 PoolWorker-8 
3 t2 PoolWorker-4 
4 t3 PoolWorker-5 
5 t4 PoolWorker-6 
6 t5 PoolWorker-7 
7 t6 PoolWorker-3 
8 t7 PoolWorker-9 
9 t8 PoolWorker-2 
10 t9 PoolWorker-8 
Should be 10 but is 10. 
+0

सुझाव के लिए धन्यवाद मुझे नहीं पता कि मैं कक्षाएं पंजीकृत कर सकता हूं - अच्छा लग रहा है। मैं इस तरह कुछ वैकल्पिक कोड बनाता हूं लेकिन मुझे नहीं पता कि यह क्यों काम कर रहा है 'counter = counter_proxy.get(); counter.update (1); counter_proxy.set (काउंटर) '- बस टाइप करके। यह समस्या नहीं है यदि आप वर्ग विशेषताओं को पढ़ते हैं तो इसे गुणों में विकसित किया जा सकता है, यह सरल उत्तर का उपयोग किया जाना चाहिए - मैं जावा पैटर्न का पालन नहीं कर रहा हूं, सभी को शुरुआत में बख्तरबंद होना चाहिए - पहले सरल होना पसंद करें - यह जावा शैलियों की तुलना में बड़े कोड की अनुमति देता है । – Chameleon

+1

@Chameleon '@ property' सजावट डिफ़ॉल्ट 'प्रॉक्सी' प्रकार के साथ काम नहीं करेगा। यदि आप वास्तव में 'मूल्य' विशेषता तक सीधे पहुंच प्राप्त करना चाहते हैं, तो [यह प्रश्न] देखें (http://stackoverflow.com/questions/26499548/accessing-an-attribute-of-a-multiprocessing-proxy-of-a -class) ऐसा करने के लिए एक तरीके के लिए। – dano

+0

यह जटिल लग रहा है। मुझे अध्ययन के उदाहरण चाहिए। ऐसा लगता है कि सच धागा पायथन की कमजोरी है - कुछ उदाहरणों के साथ बहुत अच्छा दस्तावेज भी समस्या नहीं है। अच्छा मुद्दा है कि मुझे विधियों का उपयोग करना चाहिए। – Chameleon

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