2016-12-15 16 views
7

संक्षेपफेरबदल समानांतर प्रक्रियाओं में विभिन्न अजगर वस्तुओं में क्रमश:

में मैं, समवर्ती जटिल अजगर वस्तुओं को बदलने के लिए जिससे प्रत्येक वस्तु के केवल एक ही प्रक्रिया द्वारा संसाधित किया जाता है चाहता हूँ। मैं यह कैसे कर सकता हूं (सबसे कुशलतापूर्वक)? कुछ प्रकार की पिकलिंग सहायता सहायता लागू करेगा? क्या वह कुशल होगा?

पूर्ण समस्या

मैं एक अजगर डेटा संरचना ArrayDict कि मूल रूप से एक numpy सरणी और एक शब्दकोश के होते हैं और सरणी में पंक्तियों को मनमाने ढंग से सूचकांक नक्शे की है। मेरे मामले में, सभी कुंजी पूर्णांक हैं।

a = ArrayDict() 

a[1234] = 12.5 
a[10] = 3 

print(a[1234])        #12.5 
print(a[10])         # 3.0 

print(a[1234] == a.array[a.indexDict[1234]]) #true 

अब मैं कई ऐसे ArrayDict रों हैं और उन्हें myMethod(arrayDict, params) में भरना चाहते हैं। चूंकि myMethod महंगा है, इसलिए मैं इसे समानांतर में चलाने के लिए चाहता हूं। ध्यान दें कि myMethodarrayDict पर कई पंक्तियां जोड़ सकता है। प्रत्येक प्रक्रिया अपने ArrayDict बदलती है। मुझे ArrayDict एस के समवर्ती उपयोग की आवश्यकता नहीं है।

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

मैंने साझा स्मृति और पायथन के multiprocessing मॉड्यूल पर शोध करने के लिए दिन बिताए हैं। चूंकि मैं अंततः लिनक्स पर काम कर रहा हूं, यह कार्य अपेक्षाकृत सरल लग रहा था: सिस्टम कॉल fork() कुशलतापूर्वक तर्कों की प्रतियों के साथ काम करने की अनुमति देता है। मेरा विचार तब प्रत्येक ArrayDict को अपनी प्रक्रिया में बदलने के लिए था, ऑब्जेक्ट के परिवर्तित संस्करण को वापस कर दें, और मूल ऑब्जेक्ट को ओवरराइट करें। स्मृति को सहेजने और प्रतिलिपि बनाने के लिए काम को सहेजने के लिए, मैंने में डेटा स्टोर करने के लिए sharedmem सरणी के अतिरिक्त उपयोग किया। मुझे पता है कि शब्दकोश को अभी भी कॉपी किया जाना चाहिए।

from sharedmem import sharedmem 
import numpy as np 

n = ...     # length of the data array 
myData = np.empty(n, dtype=object) 
myData[:] = [ArrayDict() for _ in range(n)] 
done = False 

while not done: 
    consideredData = ... # numpy boolean array of length 
          # n with True at the index of 
          # considered data 
    args = ...   # numpy array containing arguments 
          # for myMethod 

    with sharedmem.MapReduce() as pool: 
     results = pool.map(myMethod, 
          list(zip(myData[considered], 
            args[considered])), 
          star=True) 
     myData[considered] = results 

    done = ...    # depends on what happens in 
          # myMethod 

क्या मैं एक विभाजन गलती त्रुटि है। मैं ArrayDict से myMethod की गहरी प्रतियां बनाकर और myData में सहेजकर इस त्रुटि को बाधित करने में सक्षम था। मैं वास्तव में समझ में नहीं आता कि यह क्यों जरूरी है, और मेरे (संभावित रूप से बहुत बड़े) सरणी को प्रतिलिपि बनाना (जबकि लूप लंबे समय तक लेता है) ऐसा नहीं है जो मेरे लिए कुशल लगता है। हालांकि, कम से कम यह एक निश्चित हद तक काम किया। फिर भी, साझा प्रोग्राम के कारण तीसरे पुनरावृत्ति पर मेरे प्रोग्राम में कुछ छोटी गाड़ी का व्यवहार है। इसलिए, मुझे लगता है कि मेरा तरीका इष्टतम नहीं है।

मैंने here और here पढ़ा है कि multiprocessing.Array का उपयोग करके साझा मेमोरी पर एब्रेट्री numpy arrays को सहेजना संभव है। हालांकि, मुझे अभी भी पूरे ArrayDict को साझा करने की आवश्यकता होगी, जिसमें विशेष रूप से एक शब्दकोश शामिल है, जो बदले में नहीं है।

मैं अपने लक्ष्यों को एक कुशल तरीके से कैसे प्राप्त कर सकता हूं? क्या यह संभव है (और कुशल) मेरी वस्तु को किसी भी तरह से चुनने योग्य बनाना?

सभी समाधानों को पाइथन 3 और 64 बिट लिनक्स पर पूर्ण numpy/scipy समर्थन के साथ चलना चाहिए।

संपादित

मैं here पाया कि यह Multiprocessing "प्रबंधक" वर्गों और उपयोगकर्ता-निर्धारित प्रॉक्सी वर्गों का उपयोग मनमाने ढंग से वस्तुओं साझा करने के लिए किसी भी तरह संभव है। क्या यह कुशल होगा? मैं इसका फायदा उठाना चाहता हूं कि मुझे वस्तुओं की समवर्ती पहुंच की आवश्यकता नहीं है, भले ही उन्हें मुख्य प्रक्रिया में संभाला न जाए। क्या यह प्रत्येक ऑब्जेक्ट के लिए प्रबंधक बनाने का विकल्प होगा जिसे मैं संसाधित करना चाहता हूं? (मुझे अभी भी मैंगर्स कैसे काम करते हैं, इसके बारे में कुछ गलत धारणाएं हो सकती हैं।)

+0

myMethod में arrayDict को आप कैसे संशोधित या उपयोग करते हैं? (मुझे लगता है कि आपका मतलब है 'myMethod'' myFunc' नहीं?) – gauteh

+0

@ गौतहे: टाइपो के बारे में मुझे जागरूक करने के लिए धन्यवाद। मैंने इसे सही किया। मैंने myMethod में arrayDict को संशोधित करने का विवरण भी जोड़ा। – Samufi

+0

क्या यह महत्वपूर्ण है कि ArrayDict मनमानी कुंजी प्रकार ले सकता है? अन्यथा वर्ग का उपयोग उन प्रकारों का उपयोग करने के लिए किया जा सकता है जिन्हें प्रबंधक के बिना प्रक्रियाओं में आसानी से साझा किया जा सकता है। जैसा कि अब है, एक प्रबंधक का उपयोग करना सबसे अच्छा विकल्प प्रतीत होता है क्योंकि समस्या कुछ जटिल है। प्रदर्शन हानि महत्वपूर्ण नहीं हो सकती है। – gauteh

उत्तर

3

यह एक काफी जटिल वर्ग की तरह लगता है, और मैं पूरी तरह से अनुमान लगाने में सक्षम नहीं हूं कि यह समाधान आपके मामले में काम करेगा या नहीं। ऐसी जटिल कक्षा के लिए एक सरल समझौता ProcessPoolExecutor का उपयोग करना है।

यदि यह आपके प्रश्न का उत्तर नहीं देता है तो यह न्यूनतम, काम करने वाले उदाहरण के साथ अच्छा होगा।

from concurrent.futures import ProcessPoolExecutor 

import numpy as np 

class ArrayDict(): 
    keys = None 
    vals = None 

    def __init__ (self): 
    self.keys = dict() 
    self.vals = np.random.rand (1000) 

    def __str__ (self): 
    return "keys: " + str(self.keys) + ", vals: " + str(self.vals.mean()) 

def myMethod (ad, args): 
    print ("starting:", ad) 


if __name__ == '__main__': 
    l  = [ArrayDict() for _ in range (5)] 
    args = [2, 3, 4, 1, 3] 

    with ProcessPoolExecutor (max_workers = 2) as ex: 

    d = ex.map (myMethod, l, args) 

वस्तुओं cloned हैं जब बच्चे प्रक्रिया के लिए भेजा, तो आप परिणाम लौट (वस्तु में परिवर्तन वापस मुख्य प्रक्रिया के लिए प्रचार नहीं करेंगे के रूप में) और संभाल आप उन्हें कैसे संग्रहीत करना चाहते हैं की जरूरत है।

ध्यान दें कि वर्ग चर में परिवर्तन समान प्रक्रिया में अन्य ऑब्जेक्ट्स के लिए प्रचारित होंगे, उदा। यदि आपके पास प्रक्रियाओं से अधिक कार्य हैं, तो चर में परिवर्तन उसी प्रक्रिया में चल रहे उदाहरणों के बीच साझा किए जाएंगे। यह आमतौर पर अवांछित व्यवहार है।

यह समांतरता के लिए एक उच्च स्तरीय इंटरफ़ेस है। ProcessPoolExecutormultiprocessing मॉड्यूल का उपयोग करता है और केवल pickable objects के साथ उपयोग किया जा सकता है। मुझे संदेह है कि ProcessPoolExecutor में "sharing state between processes" के समान प्रदर्शन है। हुड के तहत, ProcessPoolExecutoris using multiprocessing.Process, और Pool के समान प्रदर्शन प्रदर्शित करना चाहिए (मानचित्र के साथ very long iterables का उपयोग करते समय)। ProcessPoolExecutor पायथन में समवर्ती कार्यों के लिए इच्छित भविष्य एपीआई प्रतीत होता है।

यदि आप कर सकते हैं, तो आमतौर पर ThreadPoolExecutor का उपयोग करने के लिए तेज़ होता है (जिसे केवल ProcessPoolExecutor के लिए बदला जा सकता है)। इस मामले में ऑब्जेक्ट प्रक्रियाओं के बीच साझा किया गया है, और एक अपडेट को मुख्य थ्रेड पर वापस प्रसारित किया जाएगा।

जैसा कि सबसे तेज़ विकल्प संभवतः ArrayDict को फिर से संरचना करने के लिए संभव है ताकि यह केवल उन वस्तुओं का उपयोग करे जिन्हें multiprocessing.Value या Array द्वारा प्रदर्शित किया जा सके।

यदि ProcessPoolExecutor काम नहीं करता है, और आप ArrayDict को अनुकूलित नहीं कर सकते हैं, तो आप Manager का उपयोग कर फंस सकते हैं। here कैसे करें इस पर अच्छे उदाहरण हैं।

सबसे बड़ी प्रदर्शन लाभ अक्सर myMethod में पाया जाने की संभावना है। और, जैसा कि मैंने उल्लेख किया है, प्रक्रियाओं की तुलना में is less धागे का उपयोग करने का ओवरहेड।

+0

उत्तर के लिए धन्यवाद! यह अच्छी तरह से काम करता है और मुझे ऐरेडिक्ट की आंतरिक सरणी का आदान-प्रदान करने देता है। क्या आप कुछ टिप्पणियां जोड़ सकते हैं जो हुड के नीचे चल रहा है? Multiprocessing.pool में क्या अंतर है? क्या वेरिएबल्स कॉपी किए गए हैं? मैंने देखा कि ArrayDict के पूर्णांक गुणों को समवर्ती रूप से नहीं बदला गया था, लेकिन dict की प्रविष्टियां थीं। मैं उस व्यवहार को कैसे समझ और भविष्यवाणी कर सकता हूं? इसके अलावा, मैंने देखा कि आपका समाधान विंडोज और लिनक्स के तहत सरल मामलों में काम करता है, लेकिन केवल लिनक्स पर पूर्ण ArrayDict के साथ। क्यूं कर? ओवरहेड "साथ" कथन में या "मानचित्र" विधि में बनाया गया है? – Samufi

+0

'साथ' कथन कोई अतिरिक्त ओवरहेड नहीं बनाता है। आपका मतलब क्या नहीं है समवर्ती रूप से? यह यहां एक उदाहरण के साथ उपयोगी होगा। यह अपरिवर्तनीय और mutables प्रकार से संबंधित हो सकता है। जवाब प्रदर्शन पर कुछ हद तक अद्यतन किया गया था। – gauteh

+1

चर की प्रतिलिपि बनाई गई है (लेकिन जब तक यह बदला नहीं जाता है तब तक स्मृति साझा की जाती है)। आपको ऑब्जेक्ट को कार्यकर्ता प्रक्रिया से वापस करना होगा और मूल ऑब्जेक्ट को प्रतिस्थापित करना होगा। अन्यथा, एक प्रबंधक का उपयोग करें। – gauteh

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