2009-12-01 21 views
15

मैं कई "शर्मनाक समानांतर" परियोजनाओं में भाग लेता हूं जिन्हें मैं multiprocessing मॉड्यूल के साथ समानांतर करना चाहता हूं। हालांकि, वे अक्सर बड़ी फाइलों (2 जीबी से अधिक) में पढ़ने, लाइन से लाइन को संसाधित करने, मूल गणना चलाने, और फिर परिणाम लिखने में शामिल होते हैं। फ़ाइल को विभाजित करने और पायथन के मल्टीप्रोसेसिंग मॉड्यूल का उपयोग करके इसे संसाधित करने का सबसे अच्छा तरीका क्या है? Queue या JoinableQueuemultiprocessing में उपयोग किया जाना चाहिए? या Queue मॉड्यूल खुद ही? या, क्या मुझे multiprocessing का उपयोग कर प्रक्रियाओं के पूल पर फ़ाइल को पुन: प्रयोज्य करना चाहिए? मैंने इन दृष्टिकोणों के साथ प्रयोग किया है लेकिन लाइन के आधार पर डेटा लाइन वितरण में ओवरहेड बहुत अधिक है। मैं cat file | process1 --out-file out1 --num-processes 2 | process2 --out-file out2 का उपयोग कर हल्के पाइप-फ़िल्टर डिज़ाइन पर बस गया हूं, जो पहले इनपुट के इनपुट का एक निश्चित प्रतिशत सीधे दूसरे इनपुट में पास करता है (this post देखें), लेकिन मैं पूरी तरह से पाइथन में एक समाधान रखना चाहता हूं।मल्टीप्रोसेसिंग के लिए पाइथन में बड़ी फ़ाइलों को विभाजित करने का सबसे अच्छा तरीका क्या है?

आश्चर्य की बात है कि पाइथन दस्तावेज ऐसा करने का एक वैधानिक तरीका सुझाता है (multiprocessing दस्तावेज़ीकरण में प्रोग्रामिंग दिशानिर्देशों पर एक लंबे खंड के बावजूद)।

धन्यवाद, विन्स

अतिरिक्त जानकारी: प्रति पंक्ति संसाधित करने में समय बदलता रहता है। कुछ समस्याएं तेज और मुश्किल से I/O बाध्य नहीं हैं, कुछ CPU-bound हैं। सीपीयू बाध्य, गैर-निर्भर कार्यों को समांतरता से पोस्ट प्राप्त होगा, जैसे कि एक प्रसंस्करण समारोह में डेटा आवंटित करने के अक्षम तरीके भी दीवार घड़ी के समय के मामले में फायदेमंद होंगे।

एक प्रमुख उदाहरण एक ऐसी स्क्रिप्ट है जो रेखाओं से खेतों को निकालती है, विभिन्न प्रकार के बिटवॉ झंडे के लिए जांच करती है, और एक पूरी फाइल के साथ एक पूरी तरह से नए प्रारूप में कुछ झंडे वाली रेखाएं लिखती है। यह एक I/O बाध्य समस्या की तरह लगता है, लेकिन जब मैंने इसे अपने सस्ते समवर्ती संस्करण के साथ पाइप के साथ चलाया, तो यह लगभग 20% तेज था। जब मैं इसे पूल और मानचित्र के साथ चलाता हूं, या multiprocessing में कतार यह हमेशा 100% से अधिक धीमी है।

+0

यह अन्यथा डेन्डी स्क्रिप्टिंग भाषा के बारे में मेरा एक बड़ा हिस्सा है - सरल समवर्ती गणना धागे के बिना दर्द है । निश्चित रूप से, आप इसे पूरा कर सकते हैं, लेकिन कुछ नौकरियां थ्रेड-एंड-लॉक मॉडल के साथ बहुत ही सरल हैं। –

+0

एक थ्रेडेड "समानांतर" संस्करण (मुझे विश्वास है) कभी भी तेज नहीं होगा, इस तथ्य को छोड़कर कि प्रक्रियाओं की तुलना में धागे तेजी से बना रहे हैं।जीआईएल सीपीयू-बाध्य बहुप्रचारित कार्यक्रमों के लिए एक बड़ी बाधा है। इसके अलावा, कोई म्यूटेबल ऑब्जेक्ट्स नहीं हैं जिन्हें प्रक्रियाओं/धागे के बीच साझा करने की आवश्यकता है, इसलिए मल्टीप्रोसेसिंग पर मल्टीथ्रेडिंग की वास्तव में आवश्यकता नहीं है। – Vince

+0

@ वास्तव में, यह सभी सटीक परिस्थिति पर निर्भर करेगा। आपके में, यह कभी नहीं हो सकता है। दूसरों में, यह हो सकता है। मेरा मुद्दा यह है कि अधिकांश समवर्ती परिचालनों के लिए मुझे (सी में) करने की आवश्यकता है, थ्रेड और ताले एक बहुत ही सरल मॉडल देते समय उचित आईपीसी के लिए अतिरिक्त आवश्यक उपयोग करने के लिए शायद ही कभी औचित्य साबित हुआ है। बड़ी समस्याओं के लिए जिन्हें बेहतर और विभिन्न मशीनों में स्केल करने की आवश्यकता है, यह एक अलग कहानी है। –

उत्तर

8

सर्वश्रेष्ठ आर्किटेक्चर में से एक पहले से ही लिनक्स ओएस का हिस्सा है। कोई विशेष पुस्तकालयों की आवश्यकता नहीं है।

आप एक "प्रशंसक-आउट" डिज़ाइन चाहते हैं।

  1. एक "मुख्य" प्रोग्राम पाइप द्वारा जुड़े कई उपप्रोसेसेस बनाता है।

  2. मुख्य कार्यक्रम फ़ाइल को पढ़ता है, उचित उपप्रोसेसरों को लाइनों को सौदा करने के लिए आवश्यक न्यूनतम फ़िल्टरिंग करने वाले पाइपों को लाइनें लिखता है।

प्रत्येक उपप्रोसेसर शायद अलग-अलग प्रक्रियाओं की एक पाइपलाइन होनी चाहिए जो stdin से पढ़ और लिखना चाहिए।

आपको कतार डेटा संरचना की आवश्यकता नहीं है, यह वास्तव में एक इन-मेमोरी पाइपलाइन है - दो समवर्ती प्रक्रियाओं के बीच बाइट्स की कतार।

+0

मैं पाइथन में इस दृष्टिकोण को लागू करने पर विचार करूंगा, क्योंकि मल्टीप्रोसेसिंग मॉड्यूल में पाइप हैं। जैसा कि आप मूल पोस्ट में देखते हैं, मैं इस सफलता का उपयोग शैल में बड़ी सफलता के साथ करता हूं। मैंने आश्चर्यजनक विचार किया था कि मैं पाइप के साथ डेटा समांतरता कभी हासिल नहीं कर सकता था। – Vince

+0

सरल शैल पाइप समांतरता का आदर्श रूप है। लिनक्स सबसे अच्छा करता है। यह अक्सर सही समाधान है। –

+0

यहां परिणाम है: http://github.com/vsbuffalo और 32 सीपीयू मशीन http://paste.pocoo.org/show/154252/ पर परिणाम। धन्यवाद एसएलओटी! – Vince

1

यह आपकी फ़ाइल के प्रारूप पर बहुत निर्भर करता है।

क्या इसे कहीं भी विभाजित करने का अर्थ है? या क्या आपको इसे एक नई लाइन में विभाजित करने की ज़रूरत है? या क्या आपको यह सुनिश्चित करने की ज़रूरत है कि आप इसे ऑब्जेक्ट परिभाषा के अंत में विभाजित करें?

फ़ाइल को विभाजित करने के बजाय, आपको फ़ाइल के उचित भाग पर जाने के लिए os.lseek का उपयोग करके, एक ही फ़ाइल पर एकाधिक पाठकों का उपयोग करना चाहिए।

अद्यतन: पोस्टर ने कहा कि वह नई लाइनों पर विभाजित करना चाहता है। फिर मैं निम्नलिखित का प्रस्ताव करता हूं:

मान लें कि आपके पास 4 प्रक्रियाएं हैं। फिर सरल समाधान oslseek 0%, 25%, 50% और 75% फ़ाइल के लिए है, और जब तक आप पहली नई पंक्ति को हिट नहीं करते हैं तब तक बाइट पढ़ें। यह प्रत्येक प्रक्रिया के लिए आपका शुरुआती बिंदु है। ऐसा करने के लिए आपको फ़ाइल को विभाजित करने की आवश्यकता नहीं है, बस प्रत्येक प्रक्रिया में बड़ी फ़ाइल में सही स्थान की तलाश करें और वहां से पढ़ना शुरू करें।

+0

न्यूलाइन पर विभाजित करें। – Vince

+0

मैंने आपके मामले में os.lseek का उपयोग करने के तरीके को समझाने के लिए टिप्पणी अपडेट की है। –

4

आप इस बात का जिक्र नहीं करते कि आप लाइनों को कैसे संसाधित कर रहे हैं; संभवतः जानकारी का सबसे महत्वपूर्ण टुकड़ा।

क्या प्रत्येक पंक्ति स्वतंत्र है? क्या गणना अगले पंक्ति से पहले आने वाली एक पंक्ति पर निर्भर है? क्या उन्हें ब्लॉक में संसाधित किया जाना चाहिए? प्रत्येक पंक्ति के लिए प्रसंस्करण कितनी देर तक लेता है? क्या कोई प्रसंस्करण चरण है जिसमें अंत में डेटा "सभी" शामिल होना चाहिए? या मध्यवर्ती परिणाम फेंक दिया जा सकता है और केवल एक चल रहे कुल बनाए रखा? क्या फ़ाइलों को थ्रेड की गिनती से फाइलसाइज को विभाजित करके विभाजित किया जा सकता है? या जब आप इसे संसाधित करते हैं तो यह बढ़ता है?

यदि रेखाएं स्वतंत्र हैं और फ़ाइल नहीं बढ़ती है, तो आपको केवल एक ही समन्वय की आवश्यकता है जो प्रत्येक कार्यकर्ता को "शुरुआती पते" और "लंबाई" का निर्माण करना है; वे स्वतंत्र रूप से खुले और फ़ाइल में खोज सकते हैं और फिर आपको अपने परिणामों को समन्वयित करना होगा; शायद एन परिणामों को एक कतार में वापस आने की प्रतीक्षा करके।

यदि लाइनें स्वतंत्र नहीं हैं, तो उत्तर फ़ाइल की संरचना पर निर्भर करेगा।

+0

क्षमा करें, प्रत्येक फ़ाइल स्वतंत्र है, कुछ भी निर्भर नहीं है, कुछ भी साझा नहीं किया जाता है (वैकल्पिक काउंटर को छोड़कर)। एक क्लासिक उदाहरण एक ऐसा फ़ंक्शन होता है जो एक रेखा लेता है, यह तय करता है कि वह इसे रखना चाहे या नहीं, रखी गई लाइनों पर कुछ मामूली गणना करता है, इन गणनाओं को प्रारूपित करता है, और फिर उस प्रक्रिया के लिए इन पंक्तियों को फ़ाइल में लिखें। फिर सभी फ़ाइलों को एक अलग प्रक्रिया में एक साथ संयोजित किया जा सकता है। फाइल मांग के संबंध में - पाइथन में बाइट गिनती द्वारा मांग की जाती है, जो या तो बाइट्स से मेल खाने वाली रेखाओं में जटिलता पेश कर सकती है। यह इसके लायक है? – Vince

+0

पीएस: फ़ाइल नहीं बढ़ती है, इंटरमीडिएट परिणाम एक फ़ाइल में संलग्न होते हैं (I/O लिखने के संघर्ष को रोकने के लिए प्रति प्रक्रिया एक फ़ाइल)। यह वास्तव में एक शर्मनाक समानांतर समस्या है। – Vince

1

मुझे पता है कि आपने विशेष रूप से पायथन के बारे में पूछा है, लेकिन मैं आपको हडोप (http://hadoop.apache.org/) देखने के लिए प्रोत्साहित करता हूं: यह मानचित्र और कम एल्गोरिदम लागू करता है जिसे विशेष रूप से इस तरह की समस्या का समाधान करने के लिए डिज़ाइन किया गया था।

गुड लक

+0

आपको अभी तक कोई जानकारी नहीं है अगर यह इस समस्या के लिए डिज़ाइन किया गया था। जैसा कि अन्य ने बताया है, हम समस्या के बारे में पर्याप्त नहीं जानते हैं। –

+1

@ सैन जैकिंटो ... मुझे लगता है कि "वे अक्सर बड़ी फाइलों (2 जीबी से अधिक) में पढ़ने, लाइन द्वारा लाइन को संसाधित करने, मूल गणना चलाने, और फिर परिणाम लिखने में शामिल होते हैं" यह मेरे लिए काफी अच्छा है, क्योंकि मैं नहीं हूं एक विशिष्ट कार्यान्वयन विस्तार दे रहा है, लेकिन एक सामान्य अवलोकन। मज़े करो दोस्त। – Escualo

+0

मैंने हडूप और मानचित्र/पहले कम किया है। मैं दोनों को प्यार करता हूं, और नक्शा/कम कर सकता हूं (और कुछ हद तक) यहां लागू किया जा रहा है। हैडोप कुछ एच/ओ समस्याओं को उनके एचएफएस (आईआईआरसी) के साथ हल करता है। मैं नक्शा/कम करने से पहले चरण के बारे में पूछ रहा हूं: फ़ाइल को विभाजित करने के लिए कौन सा दृष्टिकोण उस पर मैप किए गए फ़ंक्शन के लिए है। एक क़तार? एक फ़ाइल पुन: प्रयोज्य? – Vince

0

तो रन टाइम लंबा है, बजाय प्रत्येक प्रक्रिया होने एक Queue के माध्यम से अपनी अगली पंक्ति को पढ़ने, प्रक्रियाओं लाइनों के बैच को पढ़ने के लिए है। इस तरह ओवरहेड कई लाइनों (जैसे हजारों या अधिक) पर amortized है।

6

एक रणनीति प्रत्येक कार्यकर्ता को ऑफसेट असाइन करने के लिए है ताकि आपके पास आठ कार्यकर्ता प्रक्रियाएं हों, तो संख्या 0 से 7 हो। कार्यकर्ता संख्या 0 पहले रिकॉर्ड प्रक्रियाओं को पढ़ता है, फिर यह 7 छोड़ देता है और 8 वें रिकॉर्ड इत्यादि को संसाधित करता है। , कार्यकर्ता संख्या 1 दूसरे रिकॉर्ड को पढ़ता है और फिर 7 वें रिकॉर्ड को संसाधित करता है ..... 9

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

1

फ्रेड्रिक लुंड के Some Notes on Tim Bray's Wide Finder Benchmark बहुत अच्छी सलाह के साथ, एक बहुत ही समान उपयोग मामले के बारे में एक दिलचस्प पढ़ा है। कई अन्य लेखकों ने भी वही काम किया है, कुछ लेख से जुड़े हुए हैं, लेकिन हो सकता है कि आप "पायथन चौड़ा खोजक" या कुछ और ढूंढने के लिए कुछ भी करना चाहें। (multiprocessing मॉड्यूल के आधार पर कहीं भी एक समाधान था, लेकिन यह अब उपलब्ध नहीं प्रतीत होता है)

+0

यह बहुत बुरा है कि कई सबमिशन का स्रोत ट्रैक करना मुश्किल है। प्रविष्टियों से विस्तृतदर्शी/widefinder2 में सीखा जाने के लिए बहुत सारी उपयोगी तकनीकें हैं। – jmanning2k

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

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