C++ stdin से पंक्तियाँ क्यों पढ़ता है Python से धीमा? विश्लेषण और समाधान

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

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

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

परिचय: गति का विरोधाभास जिसने Stack Overflow को हिला दिया

\n\n

एक स्थिति की कल्पना करें: आप एक प्रतियोगिता की समस्या हल कर रहे हैं या एक गीगाबाइट लॉग फ़ाइल प्रोसेस कर रहे हैं। Python स्क्रिप्ट 2 सेकंड में पूरी हो जाती है। आप इसे C++ में फिर से लिखते हैं, दस गुना तेज़ी की उम्मीद करते हैं, लेकिन… आपको 10 सेकंड मिलते हैं! परिचित दर्द? यही वह प्रश्न है जिसने Stack Overflow पर हज़ारों व्यूज़ प्राप्त किए और एक पौराणिक चर्चा को जन्म दिया: "C++ में stdin से पंक्तियाँ पढ़ना Python से बहुत धीमा क्यों है?"।

\n\n

यह अजीब लगता है कि "तेज़" C++ "धीमे" Python से पंक्तियाँ पढ़ने जैसे सामान्य कार्य में हार सकता है? इसका उत्तर भाषा की गति में नहीं, बल्कि डिफ़ॉल्ट सेटिंग्स और iostream की आर्किटेक्चर में छिपा है। इस लेख में, हम अपनी स्वयं की जाँच करेंगे, C++ और Python में टेस्ट कोड लिखेंगे, समय मापेंगे और, सबसे महत्वपूर्ण, C++ में इनपुट-आउटपुट को वास्तव में तेज़ बनाना सीखेंगे।

\n\n

यह लेख सूखा सिद्धांत नहीं है, बल्कि उन सभी के लिए एक व्यावहारिक मार्गदर्शिका है जो C++ में लिखते हैं और इनपुट-आउटपुट प्रदर्शन समस्याओं का सामना करते हैं। चलिए शुरू करते हैं!

\n\n

समस्या का सार: iostream "धीमा" क्यों है?

\n\n

जब आप std::cin >> data या std::getline(std::cin, line) लिखते हैं, तो C++ डिफ़ॉल्ट रूप से कुछ ऐसा करता है जिसके बारे में कई लोगों को पता भी नहीं होता। यह अपने इनपुट-आउटपुट स्ट्रीम को C के मानक स्ट्रीम (stdin, stdout) के साथ सिंक्रोनाइज़ करता है। क्यों? संगतता के लिए: आप एक ही प्रोग्राम में printf और std::cout दोनों का उपयोग कर सकते हैं, और आउटपुट मिश्रित नहीं होगा।

\n\n

यह सिंक्रोनाइज़ेशन महंगा है। cin या cout का प्रत्येक कॉल C-स्ट्रीम की स्थिति की जाँच करता है, जो एक तेज़ बफ़र्ड ऑपरेशन को धीमे सिंक्रोनस ऑपरेशन में बदल देता है।

\n\n

Python में, सब कुछ अलग है। फ़ंक्शन input() और sys.stdin.readline() C स्तर पर अपने स्वयं के, अच्छी तरह से ऑप्टिमाइज़ किए गए बफ़रिंग का उपयोग करते हैं। कोई अतिरिक्त सिंक्रोनाइज़ेशन नहीं - बस फ़ाइल डिस्क्रिप्टर से डेटा का एक ब्लॉक पढ़ना। यही कारण है कि Python में stdin से पढ़ना "बॉक्स से बाहर" C++ की तुलना में तेज़ हो सकता है।

\n\n

प्रयोग: गति परीक्षण

\n\n

आइए इसे व्यवहार में जाँचें। हम एक सरल प्रोग्राम लिखते हैं जो stdin से 1,000,000 पंक्तियाँ पढ़ता है और उनके साथ कुछ नहीं करता (केवल पढ़ता है)। पहले C++ में "जैसा है":

\n\n
// slow_cin.cpp\n#include <iostream>\n#include <string>\n\nint main() {\n    std::ios::sync_with_stdio(false); // अभी के लिए कमेंट करें\n    std::cin.tie(nullptr);           // और यह भी\n\n    std::string line;\n    while (std::getline(std::cin, line)) {\n        // कुछ नहीं करते\n    }\n    return 0;\n}
\n\n

और अब Python में:

\n\n
# fast_python.py\nimport sys\n\ndef main():\n    for line in sys.stdin:\n        pass\n\nif __name__ == "__main__":\n    main()
\n\n

हम seq 1000000 | ./slow_cin और seq 1000000 | python3 fast_python.py के साथ परीक्षण चलाते हैं। परिणाम चौंकाने वाला होगा: ऑप्टिमाइज़ेशन के बिना C++, Python से 5-10 गुना धीमा हो सकता है! लेकिन C++ को छोड़ने में जल्दबाजी न करें - समस्या कोड की दो पंक्तियों से हल हो जाती है।

\n\n

समाधान: दो जादुई पंक्तियाँ

\n\n

C++ में इनपुट-आउटपुट को तेज़ करने के लिए बस इतना करना है कि सिंक्रोनाइज़ेशन और स्ट्रीम बाइंडिंग को बंद कर दें। main() की शुरुआत में जोड़ें:

\n\n
std::ios::sync_with_stdio(false);\nstd::cin.tie(nullptr);
\n\n

पहली पंक्ति iostream और stdio के बीच सिंक्रोनाइज़ेशन को बंद करती है। दूसरी cin को cout से अलग करती है (डिफ़ॉल्ट रूप से, प्रत्येक इनपुट ऑपरेशन से पहले cout अपना बफ़र फ्लश करता है, जो काम को धीमा करता है)। इसके बाद, आपका C++ कोड Python के बराबर, और अक्सर उससे भी तेज़ काम करेगा।

\n\n

परिणाम जाँचें

\n\n

अब हमारे परीक्षण में इन पंक्तियों को अनकमेंट करें और फिर से चलाएँ। आप देखेंगे कि C++ का प्रदर्शन बढ़ जाएगा। कुछ बेंचमार्क में, अंतर 10 गुना तक पहुँच जाता है।

ब्लॉग

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