2014-09-07 7 views
11

में समानांतर में एक फ़ाइल के सभी लाइनों को पढ़ने के लिए मैं एक Stream<String> में तेजी से संभव के रूप में के रूप में एक 1 जीबी बड़ी फाइल के सभी लाइनों पढ़ना चाहते हैं। वर्तमान में मैं इसके लिए Files(path).lines() का उपयोग कर रहा हूं। फ़ाइल को पार्स करने के बाद, मैं कुछ कंप्यूटेशंस कर रहा हूं (map()/filter()) पहले मैंने सोचा कि यह पहले से ही समानांतर में किया गया है, लेकिन ऐसा लगता है कि मैं गलत हूं: फ़ाइल को पढ़ने के दौरान, इसमें लगभग 50 सेकंड लगते हैं मेरे दोहरी सीपीयू लैपटॉप पर। हालांकि, अगर मैं बैश कमांड का उपयोग कर फ़ाइल को विभाजित करता हूं और फिर उन्हें समानांतर में संसाधित करता हूं, तो इसमें केवल 30 सेकंड लगते हैं।कैसे जावा 8

मैं निम्नलिखित संयोजनों की कोशिश की:

  1. एकल फाइल, कोई समानांतर रेखाओं() धारा ~ 50 सेकंड
  2. एकल फाइल, Files(..).lines().parallel().[...] ~ 50 सेकंड
  3. दो फ़ाइलों, कोई समानांतर रेखाओं() strean इन ~ 30 सेकंड
  4. दो फ़ाइलों, Files(..).lines().parallel().[...] ~ 30 सेकंड

मैं भाग गया मोटे तौर पर एक ही परिणाम के साथ 4 एकाधिक बार (1 या 2 सेकंड तक)। [...] मूल्यांकन को ट्रिगर करने के लिए अंत में toArray(...) के साथ मानचित्र और फ़िल्टर की एक श्रृंखला है।

निष्कर्ष यह है कि lines().parallel() का उपयोग करने में कोई अंतर नहीं है। समानांतर में दो फ़ाइलों को पढ़ने के रूप में एक छोटा सा समय लगता है, फ़ाइल को विभाजित करने से प्रदर्शन लाभ होता है। हालांकि ऐसा लगता है कि पूरी फाइल क्रमशः पढ़ी जाती है।

संपादित करें: मुझे लगता है कि मैं एक एसएसडी का उपयोग कहना चाहते हैं, इसलिए वहाँ समय की मांग करने के लिए व्यावहारिक रूप से है। फ़ाइल में कुल 1658652 (अपेक्षाकृत छोटी) रेखाएं हैं। विभाजन बैश में फाइल के बारे में 1.5 सेकंड लेता है: time split -l 829326 file # 829326 = 1658652/2 split -l 829326 file 0,14s user 1,41s system 16% cpu 9,560 total

तो मेरे सवाल है, वहाँ किसी भी वर्ग या जावा 8 JDK जो यह पहली बार विभाजित करने के लिए बिना सभी लाइनों को पढ़ने parallelize सकते में समारोह है? उदाहरण के लिए, अगर मैं दो सीपीयू कोर है, पहली पंक्ति पाठक पहली पंक्ति और लाइन (totalLines/2)+1 पर एक दूसरे से एक पर शुरू कर देना चाहिए।

+2

क्या मतलब है _ bash_ का उपयोग कर फ़ाइल को संपादित करें? साथ ही, आपको लाइनों को खोजने के लिए फ़ाइल को पढ़ना होगा। यह सिर्फ यह नहीं पता कि लाइन टर्मिनेटर कहां हैं। –

+2

@SotiriosDelimanolis आप फ़ाइल में एक मनमाना बिंदु पर जाने और पहले नई लाइन के लिए देखो और पहले पूरे क्षेत्र में सभी डेटा प्रसंस्करण के बिना इस तरह से विभाजित कर सकते हैं। –

+0

बैश में, आप 'split -l # लाइन'' का उपयोग कर सकते हैं, इसे 'wc -l' के साथ दो हिस्सों में विभाजित करने के लिए गठबंधन करें। माइकल Petch मेरा विचार :) – user3001

उत्तर

6

आपको this post से कुछ मदद मिल सकती है। फ़ाइल के वास्तविक पढ़ने को समानांतर करने की कोशिश करना शायद गलत पेड़ को भड़काना है, क्योंकि सबसे बड़ी मंदी आपकी फाइल सिस्टम (यहां तक ​​कि एक एसएसडी पर भी होगी)।

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

+0

मैंने परीक्षण के लिए उपयोग की गई विधि को बदल दिया, मुझे गलत लगता है, क्योंकि मैंने परिणामस्वरूप स्ट्रीम पर अंतिम ऑपरेशन (प्रत्येक (System.out :: println) के लिए गलती से परिणाम आकार को 200 तक सीमित कर दिया था। दरअसल, Files.lines (पथ) दिए गए फ़ाइल को अनुक्रमिक धारा के रूप में पढ़ता है। इसके अलावा, अधिकांश समय वास्तव में फाइल पढ़ने में व्यतीत होता था, न कि गणनाओं पर, साथ ही मैं कुछ जीसी समस्याओं में भाग गया। मैंने टाइम.लाइन (पथ) .toArray() बनाम बना दिया। मैपडबेट बफर (रीडोनली, 0, फाइल.size) का उपयोग करने वाली एक विधि। परिणाम वास्तव में काफी समान थे, मैप्डबेट बफर यहां थोड़ा धीमा था। – user3001

+0

@ user3001, आपका अंतिम रिज़ॉल्यूशन यहाँ क्या था? – daydreamer

+0

वास्तव में मुझे पता चला कि यह काफी हद तक स्ट्रीम में डेटा के साथ आप क्या करते हैं इस पर निर्भर करता है। अंत में मैंने कचरा संग्रह के साथ समस्याओं से बचने के लिए अनुक्रमिक धारा का उपयोग किया। – user3001