2012-05-19 8 views
8

में भारी, ब्रूट फोर्स अधिकतमकरण के कुशल मल्टीप्रोसेसिंग यह मेरे हालिया प्रश्न Avoiding race conditions in Python 3's multiprocessing Queues का विस्तार है। उम्मीद है कि प्रश्न का यह संस्करण अधिक विशिष्ट है।पाइथन 3

टीएल; डीआर: एक मल्टीप्रोसेसिंग मॉडल में जहां multiprocessing.Queue का उपयोग कर कार्यकर्ता प्रक्रियाओं को कतार से खिलाया जाता है, तो मेरे कार्यकर्ता इतने निष्क्रिय क्यों होते हैं? प्रत्येक प्रक्रिया में अपनी स्वयं की इनपुट कतार होती है ताकि वे एक साझा कतार के लॉक के लिए एक-दूसरे से लड़ नहीं रहे हों, लेकिन कतार वास्तव में बहुत खाली समय बिताती हैं। मुख्य प्रक्रिया आई/ओ-बाउंड थ्रेड चला रही है - क्या यह इनपुट कतारों के सीपीयू-बाउंड भरने को धीमा कर रहा है?

मैं एक निश्चित बाधा के तहत एम_आई तत्वों (= i < एन) के साथ प्रत्येक सेट के कार्टेशियन उत्पाद का अधिकतम तत्व खोजने की कोशिश कर रहा हूं। याद रखें कि कार्टेशियन उत्पाद के तत्व लंबाई-एन tuples हैं जिनके तत्व एन सेट के तत्व हैं। मैं इन tuples 'संयोजन' को इस तथ्य पर जोर देने के लिए बुलाऊंगा कि मैं मूल सेट के हर संयोजन पर लूप कर रहा हूं। जब मेरा फ़ंक्शन is_feasibleTrue देता है तो एक संयोजन बाधा को पूरा करता है। मेरी समस्या में, मैं उस संयोजन को खोजने की कोशिश कर रहा हूं जिसके तत्वों का सबसे बड़ा वजन है: sum(element.weight for element in combination)

मेरी समस्या का आकार बड़ा है, लेकिन मेरी कंपनी का सर्वर भी है। मैं समांतर एल्गोरिदम के रूप में निम्नलिखित सीरियल एल्गोरिदम को फिर से लिखने की कोशिश कर रहा हूं।

from operator import itemgetter 
from itertools import product # Cartesian product function from the std lib 
def optimize(sets): 
    """Return the largest (total-weight, combination) tuple from all 
    possible combinations of the elements in the several sets, subject 
    to the constraint that is_feasible(combo) returns True.""" 
    return max(
       map(
        lambda combination: (
         sum(element.weight for element in combination), 
         combination 
        ), 
        filter(
         is_feasible, # Returns True if combo meets constraint 
         product(*sets) 
        ) 
       ), 
       key=itemgetter(0) # Only maximize based on sum of weight 
      ) 

मेरे वर्तमान बहु दृष्टिकोण कार्यकर्ता प्रक्रियाओं बनाने और उन्हें एक इनपुट कतार के साथ संयोजन को खिलाने के लिए है। जब श्रमिक poison pill प्राप्त करते हैं तो वे आउटपुट कतार और बाहर निकलने पर सबसे अच्छा संयोजन डालते हैं। मैं मुख्य प्रक्रिया के मुख्य धागे से इनपुट कतार भरता हूं। इस तकनीक का एक फायदा यह है कि मैं मुख्य प्रक्रिया से एक माध्यमिक थ्रेड को एक निगरानी उपकरण चलाने के लिए प्रेरित कर सकता हूं (केवल एक आरपीएल मैं यह देखने के लिए उपयोग कर सकता हूं कि अब तक कितने संयोजन संसाधित किए गए हैं और कतार कितनी पूर्ण हैं)।

    +-----------+ 
      in_q0 | worker0 |----\ 
      /-------+-----------+  \ 
+-----------+ in_q1 +-----------+ \ out_q +-----------+ 
| main |-----------| worker1 |-----------| main | 
+-----------+   +-----------+/  +-----------+ 
      \-------+-----------+ /
      in_q2 | worker2 |----/ 
        +-----------+ 

मैं मूल रूप से सभी कर्मचारियों को एक इनपुट कतार से पढ़ने था, लेकिन पाया गया कि उनमें से कोई भी सीपीयू मार रहे थे। यह पता लगाना कि वे अपने पूरे समय queue.get() को अनवरोधित करने के लिए इंतजार कर रहे थे, मैंने उन्हें अपनी कतार दी। उस सीपीयू पर दबाव बढ़ गया, इसलिए मैंने पाया कि मजदूर अक्सर सक्रिय थे। हालांकि, कतारें अपना अधिकांश समय खाली खर्च करती हैं! (मैं इसे उल्लिखित निगरानी आरपीएल से जानता हूं)। यह मुझे बताता है कि कतार भरने वाला मुख्य पाश धीमा है।

from itertools import cycle 
main(): 
    # (Create workers, each with its own input queue) 
    # Cycle through each worker's queue and add a combination to that queue 
    for combo, worker in zip(product(*sets), cycle(workers)): 
     worker.in_q.put(combo) 
    # (Collect results and return) 

मेरा अनुमान है कि टोंटी worker.in_q.put() है: यहाँ है कि पाश है। मैं इसे तेज़ी से कैसे बना सकता हूं? मेरा पहला वृत्ति श्रमिकों को धीमा करना था, लेकिन यह समझ में नहीं आता ... क्या समस्या है कि मॉनिटर थ्रेड लूप को अक्सर रोक रहा है? मैं कैसे बताने में सक्षम होगा?

वैकल्पिक रूप से, क्या इसे लागू करने का एक और तरीका है जिसमें ताले पर इतनी प्रतीक्षा नहीं है?

उत्तर

4

आपके तत्व कैसा दिखते हैं? यह हो सकता है कि उन्हें कतार में रखने के लिए उन्हें चुनना धीमा है, जो स्पष्ट रूप से एक बाधा होगी। ध्यान दें कि प्रत्येक तत्व को स्वतंत्र रूप से बार-बार उठाया जा रहा है।

यदि यह मामला है, इस दृष्टिकोण मदद कर सकता है:

  • प्रमुखता के साथ एक सेट> = श्रमिकों की अपनी संख्या चुनें। आदर्श रूप में, यह श्रमिकों की संख्या से कहीं अधिक होगा।इस सेट ए को कॉल करें, और प्रत्येक कार्यकर्ता को ए के लगभग बराबर सबसेट असाइन करें। प्रेषित करें कि प्रत्येक कार्यकर्ता को सबसेट करें।
  • प्रत्येक श्रमिकों के लिए ए के अलावा सभी सेटों की पूरी सामग्री वितरित करें (संभवतः pickle.dumps के माध्यम से और फिर प्रत्येक कार्यकर्ता को समान स्ट्रिंग को प्रेषित करना, या संभवतः साझा स्मृति या अन्यथा के माध्यम से)।
  • फिर प्रत्येक कार्यकर्ता की पूर्ण जानकारी होती है जिसे इसे अपने सबसेट करने की आवश्यकता होती है। यह product(my_A_subset, *other_sets) (संभवतः अलग से आदेश दिया गया) पर अपने मजेदार तरीके से शुरू कर सकता है, प्रत्येक नौकरी (या हर तीन नौकरियों या जो कुछ भी) के बीच किसी प्रकार के स्टॉप सिग्नल के लिए मतदान। इसे कतार के माध्यम से होने की आवश्यकता नहीं है, एक-बिट साझा-स्मृति मान ठीक काम करता है।
+0

मैं _think_ मैं देख रहा हूं कि आप क्या कह रहे हैं और यदि ऐसा है तो बहुत सारी पुनर्लेखन की आवश्यकता होगी। आपके पास निश्चित रूप से मेरे लगातार 'डंपिंग' और तत्वों को लोड करने के बारे में एक बिंदु है (जो 'संग्रह। काउंटर' के उप-वर्ग के उदाहरण हैं)। अगर मैं _pre_-pickled उन्हें मदद मिलेगी? उदाहरण के लिए, 'मुख्य' में 'लूप' से पहले, 'set_of_pickles = map (lambda s: map (डंप, एस), सेट) की एक पंक्ति है,' – wkschwartz

+1

जो शायद कुछ हद तक मदद करेगी: यह पिकलिंग लागतों पर बचत करेगी , लेकिन आप अभी भी प्रति कर्मचारी केवल एक बार के बजाय आईपीसी के माध्यम से मसालेदार तारों को प्रसारित कर रहे होंगे। – Dougal