बहुक्रिया के साथ अजवाइन समानांतर वितरित कार्य


80

मेरे पास एक सीपीयू गहन सेलेरी कार्य है। मैं इस कार्य को तेजी से पूरा करने के लिए EC2 इंस्टेंसेस के बहुत से सभी प्रोसेसिंग पॉवर (कोर) का उपयोग करना चाहता हूं (बहुविकल्पी के साथ एक अजवाइन समानांतर वितरित कार्य - मुझे लगता है )

शब्द, थ्रेडिंग , मल्टीप्रोसेसिंग , वितरित कंप्यूटिंग , वितरित समानांतर प्रसंस्करण वे सभी शब्द हैं जिन्हें मैं बेहतर समझने की कोशिश कर रहा हूं।

उदाहरण कार्य:

  @app.task
  for item in list_of_millions_of_ids:
      id = item # do some long complicated equation here very CPU heavy!!!!!!! 
      database.objects(newid=id).save()

ऊपर दिए गए कोड का उपयोग करना (यदि संभव हो तो एक उदाहरण के साथ) कोई इस कार्य को वितरित करने के बारे में कैसे होगा जब यह क्लाउड में सभी उपलब्ध मशीन में सभी कंप्यूटिंग सीपीयू शक्ति का उपयोग करके इस कार्य को विभाजित करने की अनुमति देता है?


मैंने सोचा था कि MapReduce मन में आवेदन के प्रकार के लिए डिजाइन किया गया था: console.aws.amazon.com/elasticmapreduce/vnext/... :
AStopher

जवाबों:


121

आपके लक्ष्य हैं:

  1. अपने काम को कई मशीनों में वितरित करें (कंप्यूटिंग / वितरित समानांतर प्रसंस्करण वितरित)
  2. सभी सीपीयू (मल्टीप्रोसेसिंग / थ्रेडिंग) में किसी दिए गए मशीन पर काम वितरित करें

अजवाइन इन दोनों को आपके लिए काफी आसानी से कर सकता है। समझने वाली पहली बात यह है कि प्रत्येक सेलेरी कार्यकर्ता को डिफ़ॉल्ट रूप से कई कार्यों के लिए कॉन्फ़िगर किया गया है क्योंकि एक सिस्टम पर सीपीयू कोर उपलब्ध हैं:

कॉनकरीर, प्रीफ़ॉर्क वर्कर प्रक्रिया की संख्या है जो आपके कार्यों को समवर्ती रूप से संसाधित करने के लिए उपयोग की जाती है, जब ये सभी कार्य करने में व्यस्त हैं नए कार्यों को संसाधित होने से पहले समाप्त होने के लिए किसी एक कार्य के लिए इंतजार करना होगा।

डिफ़ॉल्ट कॉन्सेप्ट नंबर उस मशीन पर सीपीयू की संख्या है (कोर सहित) , आप -c विकल्प का उपयोग करके एक कस्टम नंबर निर्दिष्ट कर सकते हैं। कोई अनुशंसित मूल्य नहीं है, क्योंकि इष्टतम संख्या कई कारकों पर निर्भर करती है, लेकिन अगर आपके कार्य ज्यादातर I / O- बाध्य हैं, तो आप इसे बढ़ाने की कोशिश कर सकते हैं, प्रयोग से पता चला है कि CPU की संख्या की तुलना में दोगुना से अधिक जोड़ना संभव नहीं है। प्रभावी, और इसके बजाय प्रदर्शन को नीचा दिखाने की संभावना है।

इसका अर्थ है कि प्रत्येक व्यक्तिगत कार्य को कई सीपीयू / कोर के उपयोग के लिए मल्टीप्रोसेसिंग / थ्रेडिंग का उपयोग करने के बारे में चिंता करने की आवश्यकता नहीं है। इसके बजाय, अजवाइन प्रत्येक उपलब्ध सीपीयू का उपयोग करने के लिए समवर्ती रूप से पर्याप्त कार्य चलाएगा।

उस रास्ते से, अगला कदम एक ऐसा कार्य बनाना है जो आपके कुछ सबसेट को संसाधित करने का काम करता है list_of_millions_of_ids। आपके पास यहां कुछ विकल्प हैं - एक है प्रत्येक कार्य को एक ही आईडी संभालना है, इसलिए आप एन कार्यों को चलाते हैं, जहां N == len(list_of_millions_of_ids)। यह गारंटी देगा कि काम आपके सभी कार्यों के बीच समान रूप से वितरित किया गया है, क्योंकि कभी भी ऐसा मामला नहीं होगा जहां एक कार्यकर्ता जल्दी खत्म होता है और बस इंतजार कर रहा है; अगर इसे काम की जरूरत है, तो यह कतार से एक आईडी खींच सकता है। आप एक अजवाइन का उपयोग करके ऐसा कर सकते हैं (जॉन डो द्वारा वर्णित) group

कार्यशो:

@app.task
def process_id(item):
    id = item #long complicated equation here
    database.objects(newid=id).save()

और कार्यों को निष्पादित करने के लिए:

from celery import group
from tasks import process_id

jobs = group(process_id.s(item) for item in list_of_millions_of_ids)
result = jobs.apply_async()

एक अन्य विकल्प सूची को छोटे टुकड़ों में तोड़ना है, और अपने श्रमिकों को टुकड़े वितरित करना है। यह दृष्टिकोण कुछ चक्रों को बर्बाद करने का जोखिम चलाता है, क्योंकि आप कुछ श्रमिकों के साथ इंतजार कर सकते हैं जबकि अन्य अभी भी काम कर रहे हैं। हालाँकि, अजवाइन के दस्तावेज़ीकरण से पता चलता है कि यह चिंता अक्सर निराधार है:

कुछ लोग चिंता कर सकते हैं कि आपके कार्यों को करने से समानता का क्षरण हो सकता है, लेकिन यह व्यस्त क्लस्टर के लिए शायद ही कभी सच होता है और व्यवहार में जब आप मैसेजिंग के ओवरहेड से बच रहे होते हैं तो इससे प्रदर्शन में वृद्धि हो सकती है।

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

कार्यशो:

@app.task
def process_ids(items):
    for item in items:
        id = item #long complicated equation here
        database.objects(newid=id).save() # Still adding one id at a time, but you don't have to.

और कार्य शुरू करने के लिए:

from tasks import process_ids

jobs = process_ids.chunks(list_of_millions_of_ids, 30) # break the list into 30 chunks. Experiment with what number works best here.
jobs.apply_async()

आप इस बात पर थोड़ा प्रयोग कर सकते हैं कि किस आकार का हिस्सा आपको सबसे अच्छा परिणाम देता है। आप एक मीठा स्थान ढूंढना चाहते हैं, जहां आप मैसेजिंग ओवरहेड को काट रहे हैं, साथ ही आकार को भी छोटा रखते हुए कि आप श्रमिकों को किसी अन्य कार्यकर्ता की तुलना में बहुत तेजी से खत्म नहीं कर रहे हैं, और फिर बस कुछ भी नहीं करने के लिए इंतजार कर रहे हैं।


तो वह हिस्सा जहां मैं "जटिल सीपीयू भारी कार्य (3 डी प्रतिपादन शायद)" के साथ स्वचालित रूप से समानांतर संसाधित वितरित किया जाएगा अर्थात 1 कार्य का उपयोग सभी प्रसंस्करण शक्ति के रूप में होगा जो सभी उदाहरणों में उपलब्ध है --- और यह सब बाहर -डिब्बा? वास्तव में? वाह। पुनश्च अच्छा जवाब यह मुझे बेहतर समझाने के लिए धन्यवाद।
प्रोमेथियस

3
@ काफी नहीं। वर्तमान में लिखे गए कार्य केवल एक कोर का उपयोग कर सकते हैं। व्यक्तिगत कार्य को एक से अधिक कोर का उपयोग करने के लिए, हमें पेश करना होगा threadingया multiprocessing। ऐसा करने के बजाय, हमारे पास प्रत्येक सेलेरी कार्यकर्ता के रूप में कई कार्य हैं क्योंकि मशीन पर उपलब्ध कोर हैं (यह अजवाइन में डिफ़ॉल्ट रूप से होता है)। इसका मतलब है कि आपके पूरे क्लस्टर में, प्रत्येक कोर का उपयोग आपकी प्रक्रिया को करने के लिए किया जा सकता है list_of_million_ids, प्रत्येक कार्य को एक कोर का उपयोग करके। इसलिए एक ही कार्य के लिए कई कोर का उपयोग करने के बजाय, हम कई कार्य कर रहे हैं जिनमें से प्रत्येक एक कोर का उपयोग करते हैं। क्या इसका कोई मतलब है?
डैन

1
"एक व्यक्ति के कार्य को एक से अधिक कोर का उपयोग करने के लिए, हमें पेश करना होगा threadingया multiprocessing"। यह मानते हुए कि हम उस भारी कार्य को कई लोगों में विभाजित नहीं कर सकते, आप अजवाइन पाने के लिए थ्रेडिंग या मल्टीप्रोसेसिंग का उपयोग कैसे कर सकते हैं ताकि कई उदाहरणों के बीच कार्य को विभाजित किया जा सके? धन्यवाद
ट्रिस्टन

@ ट्रिस्टन यह इस बात पर निर्भर है कि कार्य वास्तव में क्या कर रहा है। हालाँकि, ज्यादातर मामलों में मैं यह कहूंगा कि यदि आप कार्य को उप-कार्यों में विभाजित नहीं कर सकते हैं, तो संभवतः आपके पास multiprocessingकार्य को स्वयं के अंदर से कार्य को विभाजित करने के लिए एक कठिन समय होगा , क्योंकि दोनों दृष्टिकोणों को अंततः करने की आवश्यकता होती है एक ही बात: किसी कार्य को छोटे कार्यों में विभाजित करना जो समानांतर में चलाया जा सकता है। आप वास्तव में केवल उस बिंदु को बदल रहे हैं जिस पर आप विभाजन कर रहे हैं।
डानो

1
@PirateApp यह मुद्दा कह रहा है कि आप एक अजवाइन कार्य के multiprocessing अंदर उपयोग नहीं कर सकते । अजवाइन अपने कार्यों को अलग-अलग प्रक्रियाओं में चलाने के लिए स्वयं billiard(एक multiprocessingकांटा) का उपयोग कर रहा है। फिर आपको multiprocessingउनके अंदर उपयोग करने की अनुमति नहीं है।
दानो

12

वितरण की दुनिया में केवल एक चीज है जिसे आपको सबसे ऊपर याद रखना चाहिए:

सभी बुराईयो की जड़ समयपूर्व इष्टतमीकरण है। डी। नथ द्वारा

मुझे पता है कि यह स्पष्ट लगता है लेकिन दोहरे चेक को वितरित करने से पहले आप सबसे अच्छा एल्गोरिथ्म का उपयोग कर रहे हैं (यदि यह मौजूद है ...)। यह कहते हुए कि, वितरण का अनुकूलन 3 चीजों के बीच संतुलन का कार्य है:

  1. लगातार माध्यम से डेटा लिखना / पढ़ना,
  2. मध्यम ए से मध्यम बी तक डेटा ले जाना,
  3. डाटा प्रोसेसिंग,

कंप्यूटर बनाये जाते हैं इसलिए आप अपनी प्रोसेसिंग यूनिट (3) के करीब पहुँच जाते हैं और तेज़ और अधिक कुशल (1) और (2) होगा। एक क्लासिक क्लस्टर में आदेश होगा: नेटवर्क हार्ड ड्राइव, स्थानीय हार्ड ड्राइव, रैम, प्रसंस्करण इकाई क्षेत्र के अंदर ... आजकल प्रोसेसर पर्याप्त परिष्कृत होते जा रहे हैं जिन्हें स्वतंत्र हार्डवेयर प्रसंस्करण इकाइयों का एक समूह माना जाता है जिन्हें आमतौर पर कोर कहा जाता है, ये कोर प्रक्रिया है। डेटा (3) थ्रेड्स (2) के माध्यम से। कल्पना करें कि आपका कोर इतना तेज़ है कि जब आप एक थ्रेड के साथ डेटा भेजते हैं, तो आप कंप्यूटर की 50% शक्ति का उपयोग कर रहे हैं, यदि कोर में 2 धागे हैं तो आप 100% का उपयोग करेंगे। प्रति कोर दो थ्रेड्स को हाइपर थ्रेडिंग कहा जाता है, और आपके ओएस को प्रति हाइपर थ्रेडेड कोर में 2 सीपीयू दिखाई देंगे।

प्रोसेसर में थ्रेड्स को प्रबंधित करना आमतौर पर मल्टी-थ्रेडिंग कहा जाता है। ओएस से सीपीयू को प्रबंधित करना आमतौर पर मल्टी-प्रोसेसिंग कहा जाता है। एक समूह में समवर्ती कार्यों का प्रबंधन आमतौर पर समानांतर प्रोग्रामिंग कहा जाता है। क्लस्टर में निर्भर कार्यों को प्रबंधित करना आमतौर पर वितरित प्रोग्रामिंग कहा जाता है।

तो आपकी अड़चन कहां है?

  • इन (1): ऊपरी स्तर से जारी रखने और प्रवाहित करने का प्रयास करें (उदाहरण के लिए आपकी प्रोसेसिंग यूनिट के करीब, यदि नेटवर्क हार्ड ड्राइव धीमा है तो पहले स्थानीय हार्ड ड्राइव में सेव करें)
  • इन (2): यह सबसे आम है, फ़्लाई "पैकेट" पर वितरण या संपीड़ित के लिए आवश्यक संचार पैकेट से बचने की कोशिश करें (उदाहरण के लिए अगर एचडी धीमा है, तो केवल "बैच कंप्यूटेड" संदेश सहेजें और रखें राम में मध्यस्थ परिणाम)।
  • में (3): आप कर रहे हैं! आप अपने निपटान में सभी प्रसंस्करण शक्ति का उपयोग कर रहे हैं।

अजवाइन के बारे में क्या?

अजवाइन वितरित प्रोग्रामिंग के लिए एक संदेशवाहक ढांचा है, जो संचार के लिए एक ब्रोकर मॉड्यूल (2) और दृढ़ता (1) के लिए एक बैकेंड मॉड्यूल का उपयोग करेगा, इसका मतलब है कि आप सबसे अधिक अड़चनों से बचने के लिए कॉन्फ़िगरेशन को बदलकर (यदि संभव हो तो) सक्षम होंगे आपका नेटवर्क और केवल आपके नेटवर्क पर। एकल कंप्यूटर में सर्वश्रेष्ठ प्रदर्शन प्राप्त करने के लिए पहले अपना कोड प्रोफाइल करें। फिर डिफ़ॉल्ट कॉन्फ़िगरेशन और सेट के साथ अपने क्लस्टर में अजवाइन का उपयोग करें CELERY_RESULT_PERSISTENT=True:

from celery import Celery

app = Celery('tasks', 
             broker='amqp://guest@localhost//',
             backend='redis://localhost')

@app.task
def process_id(all_the_data_parameters_needed_to_process_in_this_computer):
    #code that does stuff
    return result

निष्पादन के दौरान अपने पसंदीदा निगरानी उपकरण खोलें, मैं खरगोश के लिए डिफॉल्ट का उपयोग करता हूं और अजवाइन के लिए फूल और cpus के लिए शीर्ष, आपके परिणाम आपके बैकएंड में सहेजे जाएंगे। नेटवर्क अड़चन का एक उदाहरण कार्य कतार इतनी बढ़ रही है कि वे निष्पादन में देरी करते हैं, आप मॉड्यूल या अजवाइन कॉन्फ़िगरेशन को बदलने के लिए आगे बढ़ सकते हैं, अगर आपकी अड़चन कहीं और नहीं है।


9

इसके लिए groupअजवाइन के कार्य का उपयोग क्यों नहीं किया जाता है?

http://celery.readthedocs.org/en/latest/userguide/canvas.html#groups

मूल रूप से, आपको idsविखंडू (या श्रेणियों) में विभाजित करना चाहिए और उन्हें कार्यों के एक समूह में देना चाहिए group

अधिक परिष्कृत करने के लिए, विशेष रूप से अजवाइन के कार्यों के परिणामों को एकत्र करने के लिए, मैंने chordइसी तरह के उद्देश्य के लिए सफलतापूर्वक कार्य का उपयोग किया है :

http://celery.readthedocs.org/en/latest/userguide/canvas.html#chords

settings.CELERYD_CONCURRENCYएक संख्या को बढ़ाएं जो उचित है और आप खर्च कर सकते हैं, फिर उन अजवाइन कार्यकर्ता आपके कार्यों को एक समूह या एक काम में तब तक करते रहेंगे जब तक कि काम पूरा न हो जाए।

नोट: एक बग के कारण kombu अतीत में श्रमिकों की उच्च संख्या के लिए पुन: उपयोग करने में परेशानी हुई थी, मुझे नहीं पता कि क्या यह अभी तय है। शायद यह है, लेकिन यदि नहीं, तो CELERYD_MAX_TASKS_PER_CHILD को कम करें।

मेरे द्वारा चलाए गए सरलीकृत और संशोधित कोड पर आधारित उदाहरण:

@app.task
def do_matches():
    match_data = ...
    result = chord(single_batch_processor.s(m) for m in match_data)(summarize.s())

summarizeसभी single_batch_processorकार्यों के परिणाम मिलते हैं। प्रत्येक कार्य किसी भी सेलेरी कार्यकर्ता पर चलता है, kombuवह समन्वय करता है।

अब मैं इसे प्राप्त करता हूं: single_batch_processorऔर summarizeएएलएसओ को अजवाइन के कार्य करने होते हैं, नियमित कार्य नहीं - अन्यथा निश्चित रूप से इसे समानांतर नहीं किया जाएगा (मुझे यकीन नहीं है कि कॉर्ड रचनाकार इसे स्वीकार करेगा यदि यह अजवाइन का कार्य नहीं है)।


मेरी समझ से यह कार्य को विभाजित करेगा, लेकिन बहु-कार्य के साथ अजवाइन समानांतर वितरित कार्य का उपयोग नहीं कर रहा है। यानी सभी क्लाउड मशीनों में सभी मुफ्त सीपीयू बिजली का उपयोग करना।
प्रोमेथियस

मुझे यकीन नहीं है कि ऐसा क्यों होगा - अजवाइन काम करता है जैसे कि आपके पास श्रमिकों का एक गुच्छा है, जहां वे स्थित हैं, चाहे वे किसी अन्य मशीन पर भी स्थित हों। बेशक आपको एक से अधिक कार्यकर्ता रखने की आवश्यकता है। chord(दर्जनों श्रमिकों के लिए CELERYD_CONCURRENCY के साथ == तार्किक सीपीयू / हार्डवेयर थ्रेड्स) कि कैसे मैं कई कोर पर एक समानांतर तरीके से बड़ी संख्या में लॉग फ़ाइल बैचों को संसाधित करता हूं।
LetMeSOThat4U

यह कोड का एक बहुत बड़ा उदाहरण है। do_matchesराग का इंतजार करके कार्य अवरुद्ध हो जाएगा। यह संभवत: आंशिक या पूर्ण गतिरोध का कारण बन सकता है, क्योंकि कई / सभी श्रमिक उप-कार्यों की प्रतीक्षा कर सकते हैं, जिनमें से कोई भी नहीं किया जाएगा (जैसा कि श्रमिक कड़ी मेहनत के बजाय उप-कार्य की प्रतीक्षा करते हैं)।
प्रिसकारी दिमित्री

@PrisacariDmitrii तो फिर सही समाधान क्या होगा?
LetMeSOThat4U

4

अधिक अजवाइन श्रमिकों को जोड़ने से निश्चित रूप से कार्य को निष्पादित करने में तेजी आएगी। आपके पास एक और अड़चन हो सकती है: डेटाबेस। सुनिश्चित करें कि यह एक साथ आवेषण / अपडेट को संभाल सकता है।

अपने प्रश्न के बारे में: आप अपने EC2 उदाहरणों पर एक और प्रक्रिया बताकर अजवाइन के कामगारों को जोड़ रहे हैं celeryd। आपको कितने श्रमिकों की आवश्यकता है इसके आधार पर और भी उदाहरण जोड़ना चाह सकते हैं।


> अधिक अजवाइन श्रमिकों को जोड़ने से निश्चित रूप से कार्य को निष्पादित करने में तेजी आएगी। --- क्या यह? तो आपका कहना है कि अजवाइन मेरे बिना मेरे सभी उदाहरणों के बीच एक काम को वितरित करेगी?
प्रोमेथियस

एक सेकंड रुको। मैं सिर्फ आपका कोड फिर से पढ़ता हूं और चूंकि इसके सिर्फ एक काम से यह मदद नहीं करेगा। आप प्रति आईडी (या आईडी का हिस्सा) प्रति कार्य में आग लगा सकते हैं। या आप दूसरे उत्तर में जॉन डो की सलाह का पालन करें। तब आप अजवाइन के श्रमिकों की मात्रा से लाभ उठा सकते हैं। और हां, इस मामले में आपको ज्यादा कुछ करने की जरूरत नहीं है। बस यह सुनिश्चित करें कि कार्यकर्ता समान कतारों का उपभोग करें।
टॉरस्टेन एंजेलब्रैच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.