कई प्रक्रियाओं के बीच एक परिणाम कतार साझा करना


92

multiprocessingमॉड्यूल के लिए प्रलेखन से पता चलता है कि एक कतार को एक प्रक्रिया से कैसे गुजरना है multiprocessing.Process। लेकिन मैं अतुल्यकालिक कार्यकर्ता प्रक्रियाओं के साथ एक कतार कैसे साझा कर सकता हूं apply_async? मुझे डायनेमिक जॉइनिंग या किसी और चीज की जरूरत नहीं है, श्रमिकों के लिए एक तरह से (बार-बार) अपने परिणाम वापस आधार पर रिपोर्ट करते हैं।

import multiprocessing
def worker(name, que):
    que.put("%d is done" % name)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)
    q = multiprocessing.Queue()
    workers = pool.apply_async(worker, (33, q))

इस के साथ विफल रहता है RuntimeError: Queue objects should only be shared between processes through inheritance:। मैं समझता हूं कि इसका क्या मतलब है, और मुझे अचार / अनप्लिकिंग (और सभी विशेष विंडोज प्रतिबंध) की आवश्यकता के बजाय विरासत की सलाह समझ में आती है। लेकिन यह कैसे करते हैं मैं एक तरीका है कि काम चल रहा कतार पारित? मुझे एक उदाहरण नहीं मिल रहा है, और मैंने कई विकल्पों की कोशिश की है जो विभिन्न तरीकों से विफल रहे हैं। कृपया मदद करें?

जवाबों:


133

मल्टीप्रोसेसिंग का उपयोग करने की कोशिश करें। अपनी कतार का प्रबंधन करने के लिए और विभिन्न श्रमिकों के लिए इसे सुलभ बनाने के लिए भी।

import multiprocessing
def worker(name, que):
    que.put("%d is done" % name)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)
    m = multiprocessing.Manager()
    q = m.Queue()
    workers = pool.apply_async(worker, (33, q))

यह किया, धन्यवाद! मेरे मूल कोड में async कॉल के साथ एक असंबंधित समस्या थी, इसलिए मैंने आपके उत्तर के लिए भी प्रतिलिपि की प्रतिलिपि बनाई।
एलेक्सिस

16
कोई भी स्पष्टीकरण इसके queue.Queue()लिए उपयुक्त क्यों नहीं है?
मर्गलूम

@mrloloom: queue.Queueथ्रेडिंग के लिए बनाया गया था, इन-मेमोरी लॉक्स का उपयोग करके। एक मल्टीप्रोसेस वातावरण में, प्रत्येक उपप्रकार को queue.Queue()अपने स्वयं के मेमोरी स्पेस में एक उदाहरण की अपनी प्रति मिल जाएगी , क्योंकि उपप्रोसेस स्मृति (ज्यादातर) को साझा नहीं करते हैं।
सिंह रात्रि

@alexis प्रबंधक से तत्व कैसे प्राप्त करें ()। कई श्रमिकों द्वारा इसमें डेटा डालने के बाद कतार ()?
MSS

10

multiprocessing.Poolपहले से ही साझा परिणाम-कतार है, अतिरिक्त रूप से शामिल करने की आवश्यकता नहीं है Manager.Queue। हुड के नीचे Manager.Queueएक queue.Queue(मल्टीथ्रेडिंग-कतार) एक अलग सर्वर-प्रक्रिया पर स्थित है और परदे के पीछे से उजागर हुआ है। यह पूल की आंतरिक कतार की तुलना में अतिरिक्त उपरि जोड़ता है। पूल के मूल परिणाम-संचालन पर निर्भर होने के विपरीत, इसमें परिणाम का Manager.Queueआदेश देने की गारंटी नहीं है।

कार्यकर्ता प्रक्रियाओं के साथ शुरू नहीं किया जाता है .apply_async(), यह पहले से ही होता है जब आप तुरंत करते हैं Pool। क्या है शुरू कर दिया जब आप कॉल pool.apply_async()एक नया "काम" है। पूल के कार्यकर्ता-प्रक्रियाएं multiprocessing.pool.workerहुड के तहत -function चलाते हैं । यह फ़ंक्शन पूल के आंतरिक Pool._inqueueऔर माता-पिता को वापस भेजने के परिणामों को स्थानांतरित करने के लिए नए "कार्यों" के प्रसंस्करण का ख्याल रखता है Pool._outqueue। आपके निर्दिष्ट funcको निष्पादित किया जाएगा multiprocessing.pool.workerfuncकेवल returnकुछ के लिए है और परिणाम स्वचालित रूप से माता-पिता को वापस भेज दिया जाएगा।

.apply_async() तुरंत (एसिंक्रोनस रूप से) एक AsyncResultवस्तु (उर्फ के लिए ApplyResult) लौटाता है । .get()वास्तविक परिणाम प्राप्त करने के लिए आपको उस ऑब्जेक्ट पर कॉल (ब्लॉक करना) करना होगा। एक अन्य विकल्प कॉलबैक फ़ंक्शन को पंजीकृत करना होगा , जो परिणाम तैयार होते ही निकाल दिया जाता है।

from multiprocessing import Pool

def busy_foo(i):
    """Dummy function simulating cpu-bound work."""
    for _ in range(int(10e6)):  # do stuff
        pass
    return i

if __name__ == '__main__':

    with Pool(4) as pool:
        print(pool._outqueue)  # DEMO
        results = [pool.apply_async(busy_foo, (i,)) for i in range(10)]
        # `.apply_async()` immediately returns AsyncResult (ApplyResult) object
        print(results[0])  # DEMO
        results = [res.get() for res in results]
        print(f'result: {results}')       

उदाहरण आउटपुट:

<multiprocessing.queues.SimpleQueue object at 0x7fa124fd67f0>
<multiprocessing.pool.ApplyResult object at 0x7fa12586da20>
result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

नोट: के लिए timeout-parameter निर्दिष्ट करने .get()से कार्यकर्ता के भीतर कार्य की वास्तविक प्रक्रिया नहीं रुकेगी , यह केवल प्रतीक्षा करने वाले माता-पिता को अनब्लॉक करके बढ़ाता है multiprocessing.TimeoutError


दिलचस्प है, मैं इसे प्राप्त करने का पहला प्रयास करूँगा। यह निश्चित रूप से 2012 में इस तरह से काम नहीं किया।
एलेक्सिस

@alexis Python 2.7 (2010) प्रासंगिक रूप से यहाँ केवल संदर्भ प्रबंधक और error_callback-परमीटर के लिए अनुपलब्ध है apply_async, इसलिए यह तब से नहीं बदला है।
डार्कोनॉट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.