2012-02-14 16 views
14

क्या कोई बफर की अवधारणा को और अधिक स्पष्ट रूप से समझा सकता है? मैं समझता हूं कि बफर डेटा संरचनाएं हैं जहां वर्ण संग्रहीत किए जाते हैं, और वह जगह जहां डेटा को पढ़ना है। बफर फ्लश करने का विचार क्या है?सी ++ cout और cin buffers, और सामान्य में बफर

जब एक बफर फ़्लश किया जाता है, तो क्या इसमें संग्रहीत वर्ण लिखने के कार्य का जिक्र है?

पाठ से:

To avoid the overhead of writing in response to each output request, the library uses the 
buffer to accumulate the characters to be written, and flushes the buffer, by writing its 
contents to the output device, only when necessary. By doing so, it can combine several 
output operations into a single write. 

जब 'फ्लशिंग' है कि लगभग यह ध्वनि के रूप में यदि बफर लिखा जा रहा है, लेकिन यह भी एक ही समय में मिट बनाता का जिक्र है। बस अटकलें।

तो, स्क्रीन पर देखने के लिए लिखा जाने के लिए बफर फ्लश की आवश्यकता है?

When our program writes its prompt to cout, that output goes into the buffer associated 
with the standard output stream. Next, we attempt to read from cin. This read flushes 
the cout buffer, so we are assured that our user will see the prompt. 

यहाँ, यह लग रहा है जैसे कि अंत में 'endl' का उपयोग करके यह प्रणाली इसे तुरंत लिखने के लिए की जरूरत है बताता है (हैं जिसका अर्थ है अन्यथा नहीं?) Endl क्या नहीं किया जाता है है?

Writing the value of std::endl ends the line of 
output, and then flushes the buffer, which forces the system to write to the output 
stream immediately. 
+0

इस प्रश्न से पूछा गया है और SO में बहुत समय का उत्तर दिया गया है। http://stackoverflow.com/a/4752069/1155650 –

उत्तर

2

क्या हुआ अगर, हर बार जब आप एक डिस्क फ़ाइल को एक बाइट "लिखा था" क्या होगा के बारे में सोचें अपने कार्यक्रम वास्तव में बाहर डिस्क के पास गया, वर्तमान क्षेत्र/क्लस्टर/ब्लॉक में पढ़ा है, एक बाइट बदल फिर इसे वापस भौतिक डिस्क पर लिखा था।

मैं अपने सॉफ्टवेयर सबसे अच्छा प्रदर्शन करने के मामले में के रूप में "हिमनदों" में वर्णित किया जाएगा :-)

बफरिंग कहेंगे बैचिंग अप करने का एक साधन पढ़ता है और उन्हें और अधिक कुशल बनाने के लिए लिखता है।

उदाहरण के लिए, यदि आप डिस्क फ़ाइल पर लिख रहे हैं, तो यह डिस्क तक लिखने से पहले पूर्ण 4K ब्लॉक होने तक प्रतीक्षा कर सकता है।

पढ़ते समय, इसे 4K ब्लॉक मिल सकता है भले ही आपने केवल दस बाइट्स के लिए पूछा हो, इस धारणा पर कि आप जल्द ही बाकी के लिए पूछ सकते हैं।

लिखने पर फ़्लशिंग एक बार कैश पूर्ण हो गया है या स्पष्ट रूप से अनुरोध किए जाने पर स्पष्ट रूप से होता है (या तो फ्लश कॉल के साथ या यदि आप फ़ाइल बंद करते हैं)।

ध्यान दें कि यह फ़ाइल बफरिंग केवल एक बफरिंग की तरह है, अवधारणा का उपयोग किसी भी स्थान पर किया जा सकता है जहां पढ़ने और लिखने के लिए दक्षता लाभ "चंकिंग" द्वारा किया जा सकता है।

21

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

आई/ओ के संबंध में फ्लशिंग वर्तमान में बफेट बाइट्स को अपने गंतव्य पर लिखने का संदर्भ देता है - जो भी इसका मतलब है। C++ IOStreams के लिए सदस्य फ़ंक्शन std::ostream::flush() को कॉल करने के लिए स्ट्रीम मात्रा को फ़्लश करने के लिए जो बदले में संबंधित स्ट्रीम बफर पर std::streambuf::pubsync() पर कॉल करता है (यह विस्तार से अनदेखा करता है कि स्ट्रीम वास्तव में क्लास टेम्पलेट्स हैं, उदा।std::basic_ostream<cT, traits>; इस चर्चा के उद्देश्य से इससे कोई फर्क नहीं पड़ता कि वे वर्ग टेम्पलेट्स हैं): बेस क्लास std::streambuf सी ++ का एब्स्ट्रक्शन है कि एक निश्चित धारा को कैसे संसाधित किया जाना है। यह अवधारणात्मक रूप से इनपुट और आउटपुट बफर प्लस वर्चुअल फ़ंक्शन को क्रमशः बफर पढ़ने या लिखने के लिए ज़िम्मेदार होता है। फ़ंक्शन std::streambuf::pubsync() वर्चुअल फ़ंक्शन std::streambuf::sync() पर कॉल करता है जिसे प्रत्येक स्ट्रीम बफर के लिए ओवरराइड किया जाना चाहिए जो संभावित रूप से वर्णों को बफर करता है। यही है, फ्लशिंग 0 वास्तव में इसका अर्थ यह है कि यह वर्चुअल फ़ंक्शन कैसे कार्यान्वित किया जाता है।

चाहे sync() का ओवरराइड वास्तव में कुछ करता है और यह स्पष्ट रूप से करता है कि स्ट्रीम बफर किस प्रकार दर्शाता है। उदाहरण के लिए, std::filebuf के लिए जो फ़ाइल से पढ़ने या लिखने के लिए ज़िम्मेदार है, sync() बफर की वर्तमान सामग्री लिखता है और बफर से फ़्लश वर्ण हटा देता है। यह देखते हुए कि एक फ़ाइल वास्तव में एक भौतिक फ़ाइल का प्रतिनिधित्व नहीं कर सकती है लेकिन उदा। एक अलग प्रक्रिया के साथ संवाद करने के लिए एक नामित पाइप, यह उचित व्यवहार है। दूसरी तरफ, std::stringbuf फ्लश करना जो स्ट्रीम बफर है जिसे std::string पर लिखने के लिए उपयोग किया जाता है उदा। std::ostringstream द्वारा वास्तव में कुछ भी नहीं करता है: स्ट्रिंग पूरी तरह से प्रोग्राम के भीतर है और std::string इसका मान दर्शाती है जब std::stringbuf::str() सदस्य फ़ंक्शन कहा जाता है। उपयोगकर्ता परिभाषित स्ट्रीम बफर के लिए कई अलग-अलग व्यवहार हैं। स्ट्रीम बफर की एक आम श्रेणी किसी अन्य स्ट्रीम बफर पर पास करने से पहले किसी भी तरह आउटपुट को फ़िल्टर कर रही है (उदाहरण के लिए एक लॉगिंग बफर प्रत्येक न्यूलाइन के बाद टाइम स्टैंप जोड़ सकता है)। ये आमतौर पर अगले स्ट्रीम बफर के std::streambuf::pubsync() फ़ंक्शन को कॉल करते हैं।

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

  • धारा std::cerr स्वचालित रूप से किसी भी उत्पादन प्रत्येक उत्पादन आपरेशन बुलाया जा रहा है के बाद का उत्पादन किया फ्लश करने के लिए सेट किया गया है:

    मानक सी ++ पुस्तकालय आम तौर पर स्पष्ट flushes आवश्यकता नहीं है। यह स्वरूपण ध्वज std::ios_base::unitbuf डिफ़ॉल्ट रूप से सेट होने का परिणाम है। इसे बंद करने के लिए आप std::cerr << std::nounitbuf का उपयोग कर सकते हैं या आप केवल std::clog का उपयोग कर सकते हैं जो एक ही गंतव्य पर लिखता है लेकिन यह फ़्लशिंग नहीं करता है।

  • std::istream से पढ़ते समय "बंधे" std::ostream, यदि कोई हो, तो फ्लश किया जाता है। डिफ़ॉल्ट रूप से std::coutstd::cin से जुड़ा हुआ है। यदि आप एक बंधे std::ostream स्वयं सेट करना चाहते हैं तो आप उदा। in.tie(&out) या, यदि आप एक बंधे std::ostream को हटाना चाहते हैं तो आप उदा। std::cin.tie(0)
  • जब std::ostream नष्ट हो जाता है (या जब std::ostream मानक धाराओं में से एक है तो इसे सामान्य रूप से नष्ट कर दिया जाएगा), std::ostream फ़्लश किया गया है।
  • जब एक स्ट्रीम का बफर वर्चुअल फ़ंक्शन std::streambuf::overflow() ओवरफ़्लो करेगा, जिसे आमतौर पर वर्तमान बफर (साथ ही पारित वर्ण, यदि कोई हो) के बफर को अपने गंतव्य पर लिखता है। वर्तमान बफर को साफ़ करने के लिए यह अक्सर sync() पर कॉल करके किया जाता है लेकिन फिर से किया जाता है, कंक्रीट स्ट्रीम बफर पर निर्भर करता है।

तुम भी स्पष्ट रूप से निस्तब्धता का अनुरोध कर सकते हैं एक std::ostream:

  • आप सदस्य समारोह std::ostream::flush(), उदा कॉल कर सकते हैं std::cout.flush()
  • आप सदस्य फ़ंक्शन std::streambuf::pubsync() पर कॉल कर सकते हैं, उदा। std::cout.rdbuf()->pubsync() (माना जाता है कि एक स्ट्रीम बफर सेट अप है; std::ostream::flush() पर कॉल करने से कुछ भी नहीं होगा यदि कोई स्ट्रीम बफर नहीं है)।
  • आप मैनिपुलेटर std::flush का उपयोग कर सकते हैं, उदा। std::cout << std::flush
  • आप मैनिपुलेटर std::endl का उपयोग कर सकते हैं, उदा। std::cout << std::endl स्ट्रीम करने के बाद पहले एक न्यूलाइन चरित्र लिखने के लिए। ध्यान दें कि आपको std::endlकेवल का उपयोग करना चाहिए जब आप वास्तव में आउटपुट को फ़्लश करना चाहते हैं। std::endl का उपयोग करें जब आप वास्तव में केवल लाइन का अंत बनाना चाहते हैं! उत्तरार्द्ध के लिए बस एक नया चरित्र लिखें!

किसी भी मामले में, यदि आप केवल कुछ वर्ण लिखते हैं जो धारा बफर के बफर को बहने का कारण नहीं बनाते हैं, तब तक उनके साथ कुछ भी नहीं होगा जब तक वे या तो स्पष्ट रूप से या स्पष्ट रूप से फ़्लश नहीं होते। आम तौर पर, यह कोई समस्या नहीं है क्योंकि सामान्य मामला जहां buffered आउटपुट उपलब्ध होना आवश्यक है, यानी std::cin से पढ़ने पर, std::couttie() डी से std::cin पर संभाला जाता है। जब अन्य आई/ओ तंत्रों का उपयोग किया जा रहा है तो स्पष्ट रूप से tie() संबंधित धाराओं के लिए आवश्यक हो सकता है। बफर कभी-कभी एक समस्या है यदि कार्यक्रम "क्रैश" या डिबगिंग के दौरान दावा करता है क्योंकि स्ट्रीम में कुछ आउटपुट किए गए हैं लेकिन अभी तक भेजे गए नहीं थे। इसके लिए उपाय std::unitbuf का उपयोग करना है।

+3

वाह। मैं अभी आपकी पुस्तक 'द सी ++ स्टैंडर्ड लाइब्रेरी' पढ़ रहा हूं! – rbtLong