2010-12-14 25 views
9

यह कुछ सभी प्रोग्रामिंग भाषाओं के लिए आम है? प्रिंटल के बाद कई प्रिंट करना तेजी से लगता है लेकिन सब कुछ एक स्ट्रिंग में ले जा रहा है और केवल प्रिंटिंग जो सबसे तेज़ लगता है। क्यूं कर?क्यों इतनी धीमी गति से System.out.println है?

संपादित करें: उदाहरण के लिए, जावा सभी प्रमुख संख्या 1 लाख से ऊपर एक सेकंड से भी कम समय में प्राप्त कर सकते हैं - लेकिन फिर सब बाहर उनके खुद के println पर मुद्रण मिनट लग सकते हैं! मुद्रित करने के लिए 10 बिलियन घंटे तक!

पूर्व:

package sieveoferatosthenes; 
public class Main { 
    public static void main(String[] args) { 
     int upTo = 10000000; 
     boolean primes[] = new boolean[upTo]; 
     for(int b = 0; b < upTo; b++){ 
      primes[b] = true; 
     } 
     primes[0] = false; 
     primes[1] = false; 

     int testing = 1; 

     while(testing <= Math.sqrt(upTo)){ 
      testing ++; 
      int testingWith = testing; 
      if(primes[testing]){ 
       while(testingWith < upTo){ 
        testingWith = testingWith + testing; 
        if (testingWith >= upTo){ 
        } 
        else{ 
         primes[testingWith] = false; 
        } 

       } 
      } 
     } 
     for(int b = 2; b < upTo; b++){ 
      if(primes[b]){ 
       System.out.println(b); 
      } 
     } 
    } 
} 
+0

व्याख्या करने के लिए देखभाल? मैंने हमेशा प्रिंटल को बहुत तेजी से पाया है ... – froadie

+0

@ दासवुड "लगता है"? कृपया कुछ मानक (कोड + समय) प्रस्तुत करें। – NPE

+0

यह विंडोज़ पर धीमी गति से * निक्स पर तेज़ हो जाता है। दूसरे शब्दों में, यह उन ओएस के कंसोल कार्यान्वयन है जो यहां कारक हैं। – skaffman

उत्तर

19

println, धीमी गति से नहीं है, यह होस्टिंग ऑपरेटिंग सिस्टम द्वारा प्रदान की अंतर्निहित PrintStream कि कंसोल के साथ जुड़ा हुआ है, है।

तुम खुद देख सकते हैं: एक और फाइल में एक ही textfile पाइप के साथ सांत्वना के लिए एक बड़ा पाठ फ़ाइल डंपिंग तुलना:

cat largeTextFile.txt 
cat largeTextFile.txt > temp.txt 

पठन और लेखन समान और (फ़ाइल के आकार के लिए आनुपातिक हैं हे (एन)), केवल अंतर यह है कि गंतव्य अलग है (फाइल की तुलना में कंसोल)। और यह मूल रूप से System.out के साथ समान है।


अंतर्निहित ओएस आपरेशन (एक कंसोल विंडो पर वर्ण प्रदर्शित) धीमी है क्योंकि

  1. बाइट्स है (काफी तेजी से होना चाहिए)
  2. प्रत्येक चार है सांत्वना आवेदन करने के लिए भेजे जाने के लिए (आमतौर पर) का उपयोग करते हुए एक सच्चे प्रकार फ़ॉन्ट (कि, सुंदर धीमी है विरोधी aliasing बंद के प्रदर्शन में सुधार कर सकता है, Btw)
  3. प्रदर्शित क्षेत्र आदेश दृश्यमान क्षेत्र में एक नई लाइन संलग्न करने के लिए में स्क्रॉल किया जा सकता है प्रदान करने की (सबसे अच्छा मामला: बिट ब्लॉक ट्रांसफर ओपेटी सबसे खराब मामला: पूर्ण पाठ क्षेत्र का पुन: प्रस्तुत करना)
+0

ठीक है, तो अंतर्निहित आईओ ऑपरेशन इतना धीमा क्यों है? –

+0

कंसोल आउटपुट के मामले में इसे अनुकूलित करने के लिए सैद्धांतिक रूप से संभव है? जैसे उत्पादन को बफर करने के लिए "एक पृष्ठ" कहने के लिए, तो स्क्रॉलिंग केवल एक बार किया जाना चाहिए? मुझे पता है कि आउटपुट बफरिंग की ज़िम्मेदारी असल में कंसोल कार्यान्वयन के भीतर है, बस उत्सुक है। –

2

मेरा मानना ​​है कि यह buffering की वजह से है। लेख से उद्धरण:

बफरिंग चिंताओं का एक और पहलू टर्मिनल विंडो में टेक्स्ट आउटपुट। डिफ़ॉल्ट रूप से, System.out (एक PrintStream) लाइन बफ़र, जिसका अर्थ है कि उत्पादन बफर जब एक नई पंक्ति चरित्र का सामना करना पड़ा है प्लावित किया जाता है। यह अन्तरक्रियाशीलता, जहां आप एक इनपुट शीघ्र वास्तव में किसी भी इनपुट प्रवेश करने से पहले प्रदर्शित करने के लिए करना चाहते हैं के लिए महत्वपूर्ण है।

एक उद्धरण विकिपीडिया से बफ़र्स समझा:

कंप्यूटर विज्ञान में, एक बफर, जबकि यह किसी अन्य के लिए एक जगह से ले जाया जा रहा है अस्थायी रूप से पकड़ डेटा के लिए इस्तेमाल किया स्मृति का एक क्षेत्र है।आमतौर पर, डेटा एक बफर में संग्रहीत किया जाता के रूप में यह एक इनपुट डिवाइस (जैसे एक माउस के रूप में) से लिया गया है या यह एक आउटपुट डिवाइस (जैसे वक्ताओं के रूप में)

public void println() 
को भेज दिया जाता है बस से पहले

लाइन विभाजक स्ट्रिंग लिखकर वर्तमान पंक्ति को समाप्त करें। लाइन विभाजक स्ट्रिंग को सिस्टम प्रॉपर्टी लाइन। सेपरेटर द्वारा परिभाषित किया गया है, और आवश्यक रूप से एक नईलाइन वर्ण ('\ n') नहीं है।

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

+0

फ़ाइल या कंसोल पर बफर करना वही है (वे दोनों फाइल डिस्क्रिप्टर हैं) हालांकि एक फ़ाइल 300x तेज है, जिसका मतलब है कि बफरिंग लागत काफी छोटा टुकड़ा है। –

+0

@ पीटर मुझे लगता है कि आप इसके बारे में सही हैं। स्क्रीन की तुलना में डिस्क में बहुत अधिक थ्रूपुट है? – Alfred

4

System.out एक स्थिर PrintStream कक्षा है। PrintStream, अन्य चीजों के साथ, उन तरीकों से आप शायद print() और println() और इस तरह से परिचित हैं।

यह जावा के लिए अद्वितीय नहीं है कि इनपुट और आउटपुट ऑपरेशन लंबे समय तक लेते हैं। "लंबा।" प्रिंटिंग या PrintStream पर लिखना एक सेकंड का अंश लेता है, लेकिन इस प्रिंट के 10 बिलियन से अधिक उदाहरण काफी जोड़ सकते हैं!

यही कारण है कि आपका "सब कुछ एक स्ट्रिंग में ले जाना" सबसे तेज़ है। आपका विशाल स्ट्रिंग बनाया गया है, लेकिन आप इसे केवल प्रिंट करें पर। बेशक, यह एक बड़ा प्रिंट है, लेकिन आप वास्तव में प्रिंटिंग पर समय बिताते हैं, print() या println() से जुड़े ओवरहेड पर नहीं।

जैसा कि डीवीडी पीआरडी ने उल्लेख किया है, स्ट्रिंग्स अपरिवर्तनीय हैं। इसका मतलब है कि जब भी आप किसी पुराने स्ट्रिंग को एक पुराने स्ट्रिंग को आवंटित करते हैं लेकिन संदर्भों का पुन: उपयोग करते हैं, तो आप वास्तव में पुरानी स्ट्रिंग के संदर्भ को नष्ट कर देते हैं और नए संदर्भ का निर्माण करते हैं। तो आप स्ट्रिंगबिल्डर वर्ग का उपयोग कर इस पूरे ऑपरेशन को और भी तेज कर सकते हैं, जो उत्परिवर्तनीय है। यह उस स्ट्रिंग के निर्माण से जुड़े ओवरहेड को कम करेगा जो अंततः प्रिंट करेगा।

+0

आपके उत्तर के बीच और अल्फ्रेड का उत्तर बहुत पूरा है। धन्यवाद। –

+1

स्ट्रिंग्स बनाना समस्या नहीं है। यदि आप स्ट्रिंग्स बनाते हैं तो उन्हें मुद्रित न करें, यह एक ही गति के करीब चला जाएगा। –

+0

मेरा उत्तर देखें जो दिखाता है कि फ़ाइल को स्ट्रिंग या लिखने के लिए बहुत कम समय लगता है, कंसोल को लिखने के लिए लंबे समय के कई आदेश (यहां तक ​​कि जब मानों के साथ फ़ाइल प्रदर्शित करते हैं) –

1

आपके पास समस्या यह है कि स्क्रीन पर प्रदर्शित करना बहुत सस्ता है, खासकर यदि आपके पास ग्राफिकल विंडोज/एक्स-विंडोज वातावरण (शुद्ध टेक्स्ट टर्मिनल की बजाय) है तो फ़ॉन्ट में एक अंक प्रस्तुत करना कहीं अधिक महंगा है आप जो गणना कर रहे हैं उससे ज्यादा। जब आप स्क्रीन पर डेटा को तेज़ी से प्रदर्शित कर सकते हैं, तो यह डेटा को बफर कर देता है और जल्दी से ब्लॉक करता है। यहां तक ​​कि फ़ाइल में लिखना गणना की तुलना में महत्वपूर्ण है, लेकिन स्क्रीन पर प्रदर्शित होने से इसकी 10x - 100x तेज है।

बीटीडब्ल्यू: math.sqrt() बहुत महंगा है, और एक लूप का उपयोग मॉड्यूलस i.e.% का उपयोग करने से बहुत धीमा है यह निर्धारित करने के लिए कि कोई संख्या एकाधिक है या नहीं। बिटकसेट बूलियन की तुलना में 8x अधिक कुशल हो सकता है []

यदि मैं आउटपुट को फ़ाइल में डंप करता हूं, तो यह तेज़ है, लेकिन कंसोल पर लिखना धीमा है, और यदि मैं कंसोल को लिखता हूं जो फ़ाइल को लिखा गया था इसमें लगभग उसी समय लगते हैं।

Took 289 ms to examine 10,000,000 numbers. 
Took 149 ms to toString primes up to 10,000,000. 
Took 306 ms to write to a file primes up to 10,000,000. 
Took 61,082 ms to write to a System.out primes up to 10,000,000. 

time cat primes.txt 

real 1m24.916s 
user 0m3.619s 
sys  0m12.058s 

कोड

int upTo = 10*1000*1000; 
long start = System.nanoTime(); 
BitSet nonprimes = new BitSet(upTo); 
for (int t = 2; t * t < upTo; t++) { 
    if (nonprimes.get(t)) continue; 
    for (int i = 2 * t; i <= upTo; i += t) 
     nonprimes.set(i); 
} 
PrintWriter report = new PrintWriter("report.txt"); 
long time = System.nanoTime() - start; 
report.printf("Took %,d ms to examine %,d numbers.%n", time/1000/1000, upTo); 

long start2 = System.nanoTime(); 
for (int i = 2; i < upTo; i++) { 
    if (!nonprimes.get(i)) 
     Integer.toString(i); 
} 
long time2 = System.nanoTime() - start2; 
report.printf("Took %,d ms to toString primes up to %,d.%n", time2/1000/1000, upTo); 

long start3 = System.nanoTime(); 
PrintWriter pw = new PrintWriter(new BufferedOutputStream(new FileOutputStream("primes.txt"), 64*1024)); 
for (int i = 2; i < upTo; i++) { 
    if (!nonprimes.get(i)) 
     pw.println(i); 
} 
pw.close(); 
long time3 = System.nanoTime() - start3; 
report.printf("Took %,d ms to write to a file primes up to %,d.%n", time3/1000/1000, upTo); 

long start4 = System.nanoTime(); 
for (int i = 2; i < upTo; i++) { 
    if (!nonprimes.get(i)) 
     System.out.println(i); 
} 
long time4 = System.nanoTime() - start4; 
report.printf("Took %,d ms to write to a System.out primes up to %,d.%n", time4/1000/1000, upTo); 
report.close(); 
1

आप, कंसोल विंडो पर प्रिंट कर रहे हैं एक फाइल करने के लिए नहीं, कि हत्यारा हो जाएगा।

प्रत्येक चरित्र को चित्रित किया जाना चाहिए, और प्रत्येक पंक्ति पर पूरी विंडो को स्क्रॉल करना होगा। यदि खिड़की आंशिक रूप से अन्य खिड़कियों के साथ ओवरलैड है, तो उसे क्लिपिंग भी करना है।

यह आपके कार्यक्रम के मुकाबले कहीं अधिक चक्र ले जाएगा।

आमतौर पर है कि नहीं एक बुरा कीमत अदा करने के बाद से सांत्वना उत्पादन अपने पढ़ने खुशी :)

2

मेरी System.out.println replacement पर एक नजर डालें के लिए माना जाता है है।

डिफ़ॉल्ट रूप से, System.out.print() केवल लाइन-बफर्ड है और यूनिकोड हैंडलिंग से संबंधित बहुत कुछ काम करता है। अपने छोटे बफर आकार के कारण, System.out.println() बैच मोड में कई दोहराव वाले आउटपुट को संभालने के लिए उपयुक्त नहीं है। प्रत्येक पंक्ति तुरंत फिसल जाती है। यदि आपका आउटपुट मुख्य रूप से ASCII- आधारित है तो यूनिकोड से संबंधित गतिविधियों को हटाकर, समग्र निष्पादन समय बेहतर होगा।

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