जावा में "B" प्रिंट करना "#" से धीमा क्यों है? उदाहरणों के साथ विश्लेषण

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

"B" धीमा क्यों है और "#" तेज़ क्यों है? जावा के प्रसिद्ध प्रश्न का रहस्य

\n\n

यदि आपने कभी जावा में कंसोल पर अक्षर आउटपुट करने के लिए सरल लूप लिखे हैं, तो हो सकता है कि आपने एक अजीब बात देखी हो: छोटे अक्षर 'B' को आउटपुट करना हैश '#' को आउटपुट करने की तुलना में काफी धीमा हो सकता है। यह प्रभाव एक बार Stack Overflow पर चर्चा का विषय बन गया था — इस प्रश्न को हज़ारों बार देखा गया और वोट मिले। आज हम समझेंगे कि इस घटना के पीछे क्या है, और यह Java, कंसोल इनपुट-आउटपुट और बफ़रिंग की आंतरिक कार्यप्रणाली से कैसे संबंधित है।

\n\n

प्रयोग की स्थापना

\n

कल्पना करें कि हम दो लूप चलाते हैं जो कंसोल पर 100,000 अक्षर प्रिंट करते हैं: एक लूप '#' आउटपुट करता है, दूसरा 'B'। पहली नज़र में, ऑपरेशन समान है। हालांकि, कई सिस्टम (विशेषकर Windows) पर पहला लूप ~100 ms में पूरा होता है, जबकि दूसरे में कई सेकंड लगते हैं। ऐसा क्यों?

\n

आइए इसे Java में दोहराएँ।

\n\n

परीक्षण के लिए कोड

\n
public class SlowPrintTest {\n    public static void main(String[] args) {\n        long start = System.nanoTime();\n        for (int i = 0; i < 100_000; i++) {\n            System.out.print("#");\n        }\n        long end = System.nanoTime();\n        System.out.println("\\n'#' के लिए समय: " + (end - start) / 1_000_000 + " ms");\n\n        start = System.nanoTime();\n        for (int i = 0; i < 100_000; i++) {\n            System.out.print("B");\n        }\n        end = System.nanoTime();\n        System.out.println("\\n'B' के लिए समय: " + (end - start) / 1_000_000 + " ms");\n    }\n}
\n\n

इस कोड को IDE में नहीं, बल्कि टर्मिनल में चलाएँ (उदाहरण के लिए, java SlowPrintTest के माध्यम से)। परिणाम आपको आश्चर्यचकित करेगा। Windows पर CMD के साथ अंतर 10–50 गुना हो सकता है।

\n\n

ऐसा क्यों होता है? समस्या की जड़ — फ़ॉन्ट रेंडरिंग में

\n

समस्या स्वयं System.out.print() या JVM में नहीं है। मुख्य कारण यह है कि ऑपरेटिंग सिस्टम और टर्मिनल अक्षरों के आउटपुट को कैसे संसाधित करते हैं। Java में System.out मानक आउटपुट स्ट्रीम (stdout) पर एक रैपर है। डेटा कंसोल को भेजा जाता है, लेकिन स्क्रीन पर आउटपुट की गति निम्न पर निर्भर करती है:

\n
    \n
  • अक्षर की चौड़ाई — कई पुराने कंसोल (जैसे Windows में CMD) मोनोस्पेस फ़ॉन्ट का उपयोग करते हैं, लेकिन 'B' अक्षर को '#' की तुलना में अधिक जटिल रेंडरिंग की आवश्यकता हो सकती है।
  • \n
  • स्क्रीन अपडेट — कंसोल प्रत्येक अक्षर को आउटपुट करते समय पंक्ति को पूरी तरह से पुनः चित्रित कर सकता है, न कि केवल उसे जोड़ सकता है।
  • \n
  • टर्मिनल बफ़रिंग — कुछ टर्मिनल आउटपुट को ब्लॉक में बफ़र करते हैं, लेकिन यदि किसी अक्षर को ग्लिफ़ की चौड़ाई की गणना करने की आवश्यकता होती है, तो यह काम को धीमा कर देता है।
  • \n
\n\n

यह प्रभाव रास्टर फ़ॉन्ट के साथ Windows Command Prompt (CMD) में सबसे अधिक स्पष्ट होता है। जब आप 'B' प्रिंट करते हैं, तो कंसोल ग्राफिकल मोड में अक्षर प्रदर्शित करने का प्रयास करता है, जबकि '#' के लिए यह एक सरल दृष्टिकोण का उपयोग करता है। आधुनिक टर्मिनलों (Windows Terminal, iTerm2, Alacritty) में अंतर कम ध्यान देने योग्य या अनुपस्थित हो सकता है।

\n\n

Java में बफ़रिंग की भूमिका

\n

आउटपुट ऑप्टिमाइज़ेशन का एक महत्वपूर्ण पहलू बफ़र की गई स्ट्रीम का उपयोग है। System.out डिफ़ॉल्ट रूप से बफ़र नहीं होता है (अधिक सटीक रूप से, यह JVM स्तर पर बफ़र होता है, लेकिन छोटे आकार के साथ)। print() का प्रत्येक कॉल सिस्टम कॉल write() को ट्रिगर कर सकता है, जो बहुत महंगा है। यदि हम BufferedWriter के माध्यम से बफ़रिंग जोड़ते हैं, तो प्रदर्शन बढ़ जाएगा, लेकिन अक्षरों के बीच का अंतर बना रहेगा — यह टर्मिनल की ओर से है।

\n\n
// बफ़रिंग के साथ उदाहरण\nBufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));\nfor (int i = 0; i < 100_000; i++) {\n    bw.write("#");\n}\nbw.flush();
\n\n

बफ़रिंग के साथ भी, यदि टर्मिनल 'B' को धीरे-धीरे रेंडर करता है, तो कुल समय बढ़ जाएगा। एक

ब्लॉग

पुस्तक अनुशंसाएँ