2016-04-02 7 views
5

का उपयोग MappedByteBuffer (जावा में स्मृति मैप की गई फ़ाइल) की कोशिश करने के लिए, मैं एक साधारण wc -l (पाठ फ़ाइल लाइन गिनती) डेमो लिखा है:जावा में यह "लाइन गिनती" प्रोग्राम धीमा क्यों है? MappedByteBuffer

int wordCount(String fileName) throws IOException { 
    FileChannel fc = new RandomAccessFile(new File(fileName), "r").getChannel(); 
    MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); 

    int nlines = 0; 
    byte newline = '\n'; 

    for(long i = 0; i < fc.size(); i++) { 
     if(mem.get() == newline) 
      nlines += 1; 
    } 

    return nlines; 
} 

मैं लगभग 15 एमबी (15,008,641 बाइट्स) की एक फ़ाइल पर यह कोशिश की, और 100k लाइनें। मेरे लैपटॉप पर, इसमें लगभग 13.8 sec लगता है। यह इतना धीमा क्यों है?

पूरा वर्ग कोड यहाँ है: http://pastebin.com/hXnDvZm6

यह बारे में 28 एमएस, या 490 times faster में चलता है: http://pastebin.com/t8PLRGMa

संदर्भ के लिए, मैं सी में एक ही विचार लिखा था।

जिज्ञासा से, मैंने जावा में आवश्यक रूप से वही एल्गोरिदम और एपीआई का उपयोग करके एक स्कैला संस्करण भी लिखा। यह 10 times faster चलाता है, जो बताता है कि निश्चित रूप से कुछ अजीब चल रहा है।

अद्यतन: फ़ाइल ओएस द्वारा कैश की गई है, इसलिए कोई डिस्क लोडिंग समय शामिल नहीं है।

मैं बड़ी फ़ाइलों को यादृच्छिक पहुंच के लिए मेमोरी मैपिंग का उपयोग करना चाहता था जो रैम में फिट नहीं हो सकता है। यही कारण है कि मैं सिर्फ एक BufferedReader का उपयोग नहीं कर रहा हूँ।

+0

जावा संस्करण: OpenJDK 1.8.0 मंच: लिनक्स 4.1.16 – cidermole

+0

'MappedByteBuffer' उपयोग करने के लिए गलत बात है, अपने कार्यक्रम कुछ भी लेकिन एक सादे' BufferedReader की जरूरत नहीं है '। आप 'मैप्डबेट बफर' की किसी भी उन्नत विशेषताओं का उपयोग नहीं कर रहे हैं तो इसका उपयोग क्यों करें? –

+1

मैं एक उत्तर टाइप कर रहा था, लेकिन सवाल बंद कर दिया गया था। आपका कोड धीमा है क्योंकि यह बाइट द्वारा बाइट पढ़ता है, और यह बहुत धीमा है। बफर द्वारा बफर पढ़ें, और प्रदर्शन नाटकीय रूप से बढ़ेगा। Https://gist.github.com/jnizet/21341d48f631b7f10bc657e560c0f2de का उपयोग करके, उदाहरण के लिए, व्यतीत समय 50493us है। बनाम 8646279us। आपके मूल संस्करण के लिए। लेकिन मैं सहमत हूं कि BufferedInputStream वैसे भी आसान होगा। –

उत्तर

10

कोड बहुत धीमा है, क्योंकि fc.size() को लूप में बुलाया जाता है।

जेवीएम स्पष्ट रूप से fc.size() को खत्म नहीं कर सकता है, क्योंकि फ़ाइल का आकार रन-टाइम में बदला जा सकता है। फ़ाइल आकार क्वेरी करना अपेक्षाकृत धीमी है, क्योंकि इसे अंतर्निहित फ़ाइल सिस्टम को सिस्टम कॉल की आवश्यकता होती है।

को यह बदलें
long size = fc.size(); 
    for (long i = 0; i < size; i++) { 
     ... 
    } 
+1

हाहा, मैं पूरी तरह से गलत था। यह वास्तव में कारण है। –

+1

बहुत! यह वास्तव में बेवकूफ कुछ होना था। धन्यवाद! अब 73 एमएस में चलता है, या सी प्रदर्शन के नीचे 2.6 गुना चलता है। – cidermole

+0

@cidermole JVM स्टार्टअप सहित? –

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