2012-02-24 6 views
9

मुझे एक प्रोग्राम लिखना होगा जो आउटपुट फ़ाइल में कई वर्ण लिखेंगे। मेरे कार्यक्रम को बेहतर प्रारूपण के लिए नई लाइन लिखने की भी आवश्यकता होगी। मुझे लगता है कि ofstream एक बफर स्ट्रीम है और यदि हम फ़ाइल io के लिए buffered स्ट्रीम का उपयोग करते हैं, तो हम प्रदर्शन प्राप्त करते हैं। हालांकि, अगर हम std::endl का उपयोग करते हैं तो आउटपुट फ़्लश हो जाएगा और हम buffered आउटपुट के कारण किसी भी संभावित प्रदर्शन लाभ को खो देंगे।प्रदर्शन प्राप्त करने के लिए buffered आउटपुट के लिए ऑफस्ट्रीम का उपयोग

मुझे लगता है कि अगर मैं नई लाइन के लिए '\n' का उपयोग करता हूं तो आउटपुट केवल तभी फ़्लश किया जाएगा जब हम std::endl करेंगे। क्या ये सही है? और क्या ऐसी कोई चाल है जिसका उपयोग फ़ाइल आउटपुट के दौरान प्रदर्शन लाभ प्राप्त करने के लिए किया जा सकता है?

नोट: मैं फ़ाइल लिखने के संचालन के पूरा होने पर buffered आउटपुट को फ्लश करना चाहता हूं। मुझे लगता है कि इस तरह से मैं फ़ाइल I/O को कम कर सकता हूं और इस प्रकार प्रदर्शन प्राप्त कर सकता हूं।

+0

क्या आपको फ़ाइल को फ्लश करने की आवश्यकता है या नहीं? मैं नहीं देखता कि आप फ़ाइल को कैसे फ्लश कर सकते हैं और फ़ाइल को फ्लश करने के प्रदर्शन लाभ भी प्राप्त कर सकते हैं। (यदि आप इष्टतम फ़ाइल लिखना चाहते हैं तो आपकी सबसे अच्छी शर्त शायद मेमोरी मैप की गई फ़ाइल के साथ जाना है।) – Mankarse

+0

यदि आप प्रदर्शन के बारे में चिंतित हैं, तो आपको '<<' ऑपरेटरों का बिल्कुल उपयोग नहीं करना चाहिए। आपको पर्याप्त बफर आकार या स्मृति फ़ाइल के साथ विधियों को पढ़ने और लिखने के लिए चिपकना होगा (बुद्धिमानी से किया जाना चाहिए)। आप '\ n' और std :: endl की उदारता के साथ सही हैं :) – Arunmu

उत्तर

17

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

std::endl के संबंध में मुख्य बिंदु यह है कि लोग इसे एक लाइन समाप्त करने का दुरुपयोग करते हैं जो बफर को फ्लश करने का कारण बनता है और वे प्रदर्शन के प्रभाव से अनजान हैं। std::endl का इरादा यह है कि लोगों को उचित बिंदुओं पर फ़ाइलों को फ्लश करने के लिए नियंत्रण दिया जाता है। इसके लिए प्रभावी होने के लिए उन्हें यह जानने की जरूरत है कि वे क्या कर रहे हैं। अफसोस की बात है कि std::endl के बारे में बहुत से लोग अनजान थे जिन्होंने इस लाइन को समाप्त करने के रूप में अपने उपयोग का विज्ञापन किया था, जैसे कि यह कई जगहों पर उपयोग किया जाता है जहां यह सादा गलत है।

यह कहा गया है कि नीचे कई चीजें हैं जो आप प्रदर्शन को बेहतर बनाने की कोशिश कर सकते हैं। मुझे लगता है कि आपको स्वरूपित आउटपुट की आवश्यकता है (जो std::ofstream::write() का उपयोग आपको नहीं देगा)।

  • जाहिर है, std::endl का उपयोग न करें जब तक आपको यह करना न पड़े। यदि लेखन कोड पहले से मौजूद है और कई स्थानों पर std::endl का उपयोग करता है, जिनमें से कुछ संभवतः आपके नियंत्रण से बाहर हैं, तो आप फ़िल्टरिंग स्ट्रीम बफर का उपयोग कर सकते हैं जो उचित आकार के आंतरिक बफर का उपयोग करता है और जो अंतर्निहित में sync() फ़ंक्शन पर कॉल अग्रेषित नहीं करता है स्ट्रीम बफर यद्यपि इसमें एक अतिरिक्त प्रति शामिल है, यह कुछ नकली फ्लश से बेहतर है क्योंकि ये परिमाण के अधिक महंगे हैं।
  • हालांकि इसका std::ofstream एस पर कोई प्रभाव नहीं होना चाहिए, हालांकि std::ios_base::sync_with_stdio(false) पर कुछ कार्यान्वयन पर प्रदर्शन को प्रभावित करने के लिए उपयोग किया जाता है।यदि आप इसका प्रभाव डालते हैं तो आप एक अलग IOstream कार्यान्वयन का उपयोग करना चाहते हैं क्योंकि प्रदर्शन के संबंध में शायद अधिक चीजें गलत हैं।
  • सुनिश्चित करें कि आप std::locale का उपयोग कर रहे हैं जिसका std::codecvt<...>true देता है जब always_noconv() पर कॉल किया जाता है। std::use_facet<std::codecvt<char, char, stdd::mbstate_t> >(out.get_loc()).always_noconv() का उपयोग कर इसे आसानी से चेक किया जा सकता है। std::locale को पकड़ने के लिए आप std::locale("C") का उपयोग कर सकते हैं जिसके लिए यह सच होना चाहिए।
  • कुछ लोकेल कार्यान्वयन उनके संख्यात्मक पहलुओं के बहुत अक्षम कार्यान्वयन का उपयोग करते हैं और भले ही वे उचित रूप से अच्छे हैं, std::num_put<char> पहलू का डिफ़ॉल्ट कार्यान्वयन अभी भी उन चीजों को कर सकता है जिनकी आपको वास्तव में आवश्यकता नहीं है। विशेष रूप से यदि आपका न्यूमेरिक स्वरूपण उचित रूप से सरल है, यानी आप स्वरूपण झंडे को बदलना नहीं रखते हैं, तो आपने वर्णों के मैपिंग को प्रतिस्थापित नहीं किया है (यानी आप एक अजीब std::ctype<char> पहलू का उपयोग नहीं करते हैं) आदि। कस्टम का उपयोग करना उचित हो सकता है std::num_put<char> पहलू: पूर्णांक प्रकारों के लिए तेज़ लेकिन सरल प्रारूपण फ़ंक्शन बनाना और फ़्लोटिंग पॉइंट्स के लिए एक अच्छा स्वरूपण फ़ंक्शन बनाना आसान है जो आंतरिक रूप से snprintf() का उपयोग नहीं करता है।

कुछ लोगों ने मेमोरी मैप की गई फ़ाइलों का उपयोग करने का सुझाव दिया है, लेकिन यह केवल तभी काम करता है जब लक्ष्य फ़ाइल का आकार अग्रिम में जाना जाता है। यदि ऐसा है तो यह प्रदर्शन में सुधार करने का एक शानदार तरीका है अन्यथा यह परेशान करने योग्य नहीं है। ध्यान दें कि आप मेमोरी मैप किए गए फ़ाइलों (या अधिक सामान्यतः किसी भी प्रकार के आउटपुट इंटरफ़ेस के साथ) के साथ स्ट्रीम स्वरूपण का उपयोग कर सकते हैं कस्टम std::streambuf जो मेमोरी मैपिंग इंटरफ़ेस का उपयोग करता है। std::istream एस के साथ उनका उपयोग करते समय मुझे स्मृति मैपिंग कभी-कभी प्रभावी होती है। कई मामलों में मतभेद वास्तव में ज्यादा मायने रखते हैं।

बहुत समय पहले मैंने अपना खुद का आईओएसट्रीम और लोकेशन कार्यान्वयन लिखा था जो ऊपर वर्णित कुछ प्रदर्शन समस्याओं से ग्रस्त नहीं है (यह my site से उपलब्ध है लेकिन यह लगभग थोड़ा है और मैंने इसे लगभग छुआ नहीं है अब 10 साल)। इस कार्यान्वयन पर अभी भी बहुत सी चीजें सुधारी जा सकती हैं लेकिन मेरे पास अद्यतित कार्यान्वयन नहीं है जिसे मैं कहीं भी पोस्ट करने के लिए तैयार हूं। जल्द ही, उम्मीद है - लगभग 10 वर्षों से मैं कुछ सोच रहा हूं, हालांकि ...

+0

@ कुहल अच्छा स्पष्टीकरण के लिए बहुत बहुत धन्यवाद। चूंकि std :: endl का उपयोग अब मेरे नियंत्रण में है, मैं std :: endl का उपयोग नहीं करूंगा।मैं नई लाइन के लिए \ n उपयोग करूंगा। मुझे आशा है कि इससे मुझे बेहतर प्रदर्शन मिलेगा। और, आप प्रारूपित आउटपुट के लिए मेरी ज़रूरत के बारे में सही जगह पर हैं। – learningstack

3

\n प्रिंटिंग (आवश्यक रूप से) आउटपुट फ्लश नहीं करेगा, जबकि std::endl या std::flush प्रिंटिंग होगा।

आप तेजी से लेखन चाहते हैं और कोई परवाह नहीं है अगर डेटा उपलब्ध होने तक आप पूरी तरह से पूरा कर लें, तो \n के साथ अपने लेखन के सभी करते हैं और इसके बारे में चिंता नहीं है (के बाद से closing the file भी धारा फ्लश) यदि ।

यदि आपको अभी भी प्रदर्शन नहीं मिल रहा है, तो आप fstream::read(char*, int) का उपयोग कर सकते हैं - यह आपको इच्छित आकार ब्लॉक में डेटा पढ़ने देता है (बड़े ब्लॉक को आजमाएं और देखें कि यह मदद करता है)।

0

हाँ, endl स्ट्रीम को फ़्लश करता है। बड़ी फ़ाइलों के लिए इसका इस्तेमाल न करें।

यह भी सुनिश्चित करें कि स्ट्रीम बफर सेट करना सुनिश्चित करें। कम से कम एमएसवीसी कार्यान्वयन 1 char एक समयfilebuf पर जब कोई बफर सेट नहीं होता है (streambuf::xsputn देखें)। यह आपके एप्लिकेशन को सीपीयू-बाउंड बना सकता है, जिसके परिणामस्वरूप निम्न I/O दरें होंगी।

तो, लेखन करने से पहले अपने कोड के लिए कुछ इस तरह जोड़ें:

char buf[256 * 1024]; 
mystream.rdbuf()->pubsetbuf(buf, sizeof(buf)); 

एनबी: आप एक पूरा नमूना आवेदन here पा सकते हैं।

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