क्या सी ++ मानक iostreams के लिए खराब प्रदर्शन को अनिवार्य करता है, या क्या मैं सिर्फ एक खराब कार्यान्वयन से निपट रहा हूं?


197

जब भी मैं C ++ मानक पुस्तकालय iostreams के धीमे प्रदर्शन का उल्लेख करता हूं, तो मुझे अविश्वास की लहर के साथ मिलता है। फिर भी मेरे पास प्रोइलर परिणाम हैं, जो आईओस्ट्रीम लाइब्रेरी कोड (पूर्ण कंपाइलर ऑप्टिमाइज़ेशन) में बड़ी मात्रा में समय बिताते हैं, और आईओट्रीम से ओएस-विशिष्ट I / O एपीआई और कस्टम बफर प्रबंधन पर स्विच करने से परिमाण में सुधार का आदेश मिलता है।

C ++ मानक पुस्तकालय क्या अतिरिक्त काम कर रहा है, क्या यह मानक द्वारा आवश्यक है, और क्या यह व्यवहार में उपयोगी है? या कुछ कंपाइलर iostreams के कार्यान्वयन को प्रदान करते हैं जो मैनुअल बफर प्रबंधन के साथ प्रतिस्पर्धी हैं?

मानक

गतिमान मामलों को प्राप्त करने के लिए, मैंने कुछ छोटे कार्यक्रमों के लिए लिखा है जो आईस्ट्रीम आंतरिक बफरिंग का अभ्यास करते हैं:

  • एक http://ideone.com/2PPYw में बाइनरी डेटा डाल रहा हैostringstream
  • बाइनरी डेटा को एक char[]बफर में डालना http://ideone.com/Ni5ct
  • एक http://ideone.com/Mj2Fivector<char> का उपयोग करके बाइनरी डेटा डाल रहा हैback_inserter
  • नया : vector<char>सरल पुनरावृत्ति http://ideone.com/9iitv
  • नई : http://ideone.com/qc9QA में सीधे बाइनरी डेटा डाल रहा हैstringbuf
  • नई : vector<char>सरल पुनरावृत्ति प्लस सीमा की जाँच करें http://ideone.com/YyrKy

ध्यान दें कि ostringstreamऔर stringbufसंस्करण कम पुनरावृत्तियों चलाते हैं क्योंकि वे बहुत धीमे हैं।

आइडोन पर, + + ostringstreamकी तुलना में लगभग 3 गुना धीमा है , और कच्चे बफर की तुलना में लगभग 15 गुना धीमा है । यह पहले और बाद की रूपरेखा के अनुरूप है जब मैंने अपने असली एप्लिकेशन को कस्टम बफरिंग में बदल दिया।std:copyback_inserterstd::vectormemcpy

ये सभी इन-मेमोरी बफ़र हैं, इसलिए आईस्ट्रीम की सुस्ती को धीमी डिस्क I / O पर दोष नहीं दिया जा सकता है, बहुत अधिक निस्तब्धता, stdio के साथ सिंक्रनाइज़ेशन, या किसी भी अन्य चीज का उपयोग करने के लिए लोग C ++ मानक पुस्तकालय की मनाया सुस्ती का उपयोग करते हैं iostream।

अन्य प्रणालियों पर बेंचमार्क देखना और उन चीजों पर टिप्पणी करना अच्छा होगा जो सामान्य कार्यान्वयन करते हैं (जैसे कि gcc के libc ++, विजुअल C ++, Intel C ++) और मानक द्वारा कितना ओवरहेड अनिवार्य है।

इस परीक्षण के लिए तर्क

कई लोगों ने सही ढंग से बताया है कि आमतौर पर स्वरूपित आउटपुट के लिए आईस्ट्रीम का अधिक उपयोग किया जाता है। हालाँकि, वे बाइनरी फ़ाइल एक्सेस के लिए C ++ मानक द्वारा प्रदान किया गया एकमात्र आधुनिक API भी हैं। लेकिन आंतरिक बफरिंग पर प्रदर्शन परीक्षण करने का असली कारण I / O के विशिष्ट स्वरूपित पर लागू होता है: यदि iostreams कच्चे डेटा के साथ आपूर्ति की गई डिस्क नियंत्रक को नहीं रख सकते हैं, तो संभवतः जब वे प्रारूपण के लिए जिम्मेदार होते हैं, तो वे कैसे रख सकते हैं?

बेंचमार्क समय

ये सभी बाहरी ( k) लूप के प्रति पुनरावृत्ति हैं ।

Ideone पर (gcc-4.3.4, अज्ञात OS और हार्डवेयर):

  • ostringstream: 53 मिली सेकेंड
  • stringbuf: 27 मि
  • vector<char>और back_inserter: 17.6 एमएस
  • vector<char> साधारण पुनरावृत्ति के साथ: 10.6 मि
  • vector<char> पुनरावृत्ति और सीमा जाँच: 11.4 मि
  • char[]: 3.7 मि

मेरे लैपटॉप पर (विजुअल C ++ 2010 x86,, cl /Ox /EHscविंडोज 7 अल्टीमेट 64-बिट, इंटेल कोर i7, 8 जीबी रैम):

  • ostringstream: 73.4 मिलीसेकंड, 71.6 मिसे
  • stringbuf: 21.7 एमएस, 21.3 एमएस
  • vector<char>और back_inserter: 34.6 एमएस, 34.4 एमएस
  • vector<char> साधारण पुनरावृत्ति के साथ: 1.10 एमएस, 1.04 एमएस
  • vector<char> पुनरावृत्ति और सीमा जाँच: 1.11 एमएस, 0.87 एमएस, 1.12 एमएस, 0.89 एमएस, 1.02 एमएस, 1.14 एमएस
  • char[]: 1.48 एमएस, 1.57 एमएस

Visual C ++ 2010 x86, प्रोफ़ाइल-गाइडेड अनुकूलन के साथ cl /Ox /EHsc /GL /c, link /ltcg:pgi, रन link /ltcg:pgo, उपाय:

  • ostringstream: 61.2 एमएस, 60.5 एमएस
  • vector<char> साधारण पुनरावृत्ति के साथ: 1.04 एमएस, 1.03 एमएस

एक ही लैपटॉप, एक ही OS, जो साइबर 4.3 gcc का उपयोग कर रहा है g++ -O3:

  • ostringstream: 62.7 एमएस, 60.5 एमएस
  • stringbuf: 44.4 एमएस, 44.5 एमएस
  • vector<char>और back_inserter: 13.5 एमएस, 13.6 एमएस
  • vector<char> साधारण पुनरावृत्ति के साथ: 4.1 एमएस, 3.9 एमएस
  • vector<char> पुनरावृत्ति और सीमा की जाँच करें: 4.0 एमएस, 4.0 एमएस
  • char[]: 3.57 एमएस, 3.75 एमएस

समान लैपटॉप, विजुअल C ++ 2008 SP1 cl /Ox /EHsc:

  • ostringstream: 88.7 एमएस, 87.6 एमएस
  • stringbuf: 23.3 एमएस, 23.4 एमएस
  • vector<char>और back_inserter: 26.1 एमएस, 24.5 एमएस
  • vector<char> साधारण पुनरावृत्ति के साथ: 3.13 एमएस, 2.48 एमएस
  • vector<char> पुनरावृति और सीमा जाँच: 2.97 एमएस, 2.53 एमएस
  • char[]: 1.52 एमएस, 1.25 एमएस

एक ही लैपटॉप, विजुअल C ++ 2010 64-बिट संकलक:

  • ostringstream: 48.6 एमएस, 45.0 एमएस
  • stringbuf: 16.2 एमएस, 16.0 एमएस
  • vector<char>और back_inserter: 26.3 एमएस, 26.5 एमएस
  • vector<char> साधारण पुनरावृत्ति के साथ: 0.87 एमएस, 0.89 एमएस
  • vector<char> पुनरावृति और सीमा जाँच: 0.99 एमएस, 0.99 एमएस
  • char[]: 1.25 एमएस, 1.24 एमएस

संपादित करें: परिणाम देखने के लिए लगातार दो बार दौड़े। सुंदर लगातार IMO।

नोट: मेरे लैपटॉप पर, चूंकि मैं विचारधारा की अनुमति देने की तुलना में अधिक सीपीयू समय को छोड़ सकता हूं, इसलिए सभी तरीकों के लिए पुनरावृत्तियों की संख्या 1000 तक निर्धारित करता हूं। इसका मतलब यह है कि ostringstreamऔर vectorवास्तविककरण, जो केवल पहले पास पर होता है, अंतिम परिणामों पर बहुत कम प्रभाव पड़ता है।

संपादित करें: उफ़, एक बग के vectorसाथ-साधारण-इटरेटर में पाया गया, इटरेटर उन्नत नहीं था और इसलिए बहुत सारे कैश हिट थे। मैं सोच रहा था कि कैसे vector<char>बेहतर प्रदर्शन कर रहा था char[]। हालांकि इससे बहुत फर्क नहीं पड़ा, लेकिन vector<char>यह अभी भी char[]VC ++ 2010 के मुकाबले तेज है ।

निष्कर्ष

आउटपुट स्ट्रीम की बफरिंग के लिए हर बार डेटा संलग्न होने के लिए तीन चरणों की आवश्यकता होती है:

  • जांचें कि आने वाला ब्लॉक उपलब्ध बफर स्थान को फिट बैठता है।
  • आने वाले ब्लॉक को कॉपी करें।
  • डेटा-प्वाइंटर के अंत का अद्यतन करें।

नवीनतम कोड स्निपेट मैंने पोस्ट किया, " vector<char>सिंपल इटरेटर प्लस बाउंड चेक" न केवल ऐसा करता है, यह अतिरिक्त स्थान भी आवंटित करता है और मौजूदा डेटा को स्थानांतरित करता है जब आने वाला ब्लॉक फिट नहीं होता है। जैसा कि क्लिफोर्ड ने बताया, एक फ़ाइल I / O वर्ग में बफरिंग को ऐसा नहीं करना होगा, यह सिर्फ वर्तमान बफर को फ्लश करेगा और इसका पुन: उपयोग करेगा। तो यह बफरिंग आउटपुट की लागत पर एक ऊपरी बाध्य होना चाहिए। और यह वही है जो काम करने वाले मेमोरी बफर को बनाने के लिए आवश्यक है।

तो stringbufideone पर 2.5x धीमा क्यों है , और जब मैं इसका परीक्षण करता हूं तो कम से कम 10 गुना धीमा होता है? इस सरल माइक्रो-बेंचमार्क में इसका उपयोग पॉलीमॉर्फिक रूप से नहीं किया जा रहा है, ताकि इसकी व्याख्या न हो।


24
आप एक बार में एक लाख वर्ण लिख रहे हैं, और सोच रहे हैं कि यह उपदेशात्मक बफर की नकल करने की तुलना में धीमा क्यों है?
आनन।

20
@ बंदूक: मैं चार मिलियन बाइट्स चार-ए-समय पर कर रहा हूं, और हां मैं सोच रहा हूं कि यह धीमा क्यों है। अगर std::ostringstreamतेजी से अपने बफर आकार को बढ़ाने के लिए स्मार्ट नहीं std::vectorहै, तो वह (ए) बेवकूफ और (बी) I / O प्रदर्शन के बारे में सोचने वाले कुछ लोगों को सोचना चाहिए। वैसे भी, बफर का पुन: उपयोग हो जाता है, यह हर बार वास्तविक नहीं मिलता है। और std::vectorएक गतिशील रूप से बढ़ते बफर का उपयोग भी कर रहा है। मैं यहां निष्पक्ष रहने की कोशिश कर रहा हूं।
बेन वोइगट

14
आप वास्तव में किस कार्य को बेंचमार्क करने की कोशिश कर रहे हैं? यदि आप किसी भी स्वरूपण सुविधाओं का उपयोग नहीं कर रहे हैं ostringstreamऔर आप जितना संभव हो उतना तेज़ प्रदर्शन चाहते हैं तो आपको सीधे जाने पर विचार करना चाहिए stringbufostreamवर्गों लचीला बफर विकल्प (फ़ाइल, स्ट्रिंग, आदि) के माध्यम से के साथ एक साथ लोकेल बारे में पता स्वरूपण कार्यक्षमता टाई लगता है कर रहे हैं rdbuf()और इसके आभासी समारोह इंटरफ़ेस। यदि आप कोई स्वरूपण नहीं कर रहे हैं, तो उस अप्रत्यक्ष स्तर का अतिरिक्त निश्चित रूप से अन्य दृष्टिकोणों की तुलना में आनुपातिक रूप से महंगा दिखने वाला है।
सीबी बेली

5
सत्य सेशन के लिए +1। हम से ले जाकर आदेश या परिमाण गति अप मिल गया है ofstreamकरने के लिए fprintfजब प्रवेश युगल शामिल जानकारी outputting। WinXPsp3 पर MSVC 2008। iostreams सिर्फ कुत्ता धीमा है।
KitsuneYMG

6
यहाँ समिति की साइट पर कुछ परीक्षण है: open-std.org/jtc1/sc22/wg21/docs/D_5.cpp
Johannes Schaub - litb

जवाबों:


49

शीर्षक के रूप में आपके प्रश्न की बारीकियों का इतना जवाब न देना: 2006 की C ++ प्रदर्शन की तकनीकी रिपोर्ट में IOStreams (p.68) पर एक दिलचस्प खंड है। आपके प्रश्न के लिए सबसे अधिक प्रासंगिक धारा 6.1.2 ("निष्पादन गति") में है:

चूंकि IOStreams प्रसंस्करण के कुछ पहलुओं को कई पहलुओं पर वितरित किया जाता है, ऐसा प्रतीत होता है कि मानक एक अक्षम कार्यान्वयन को अनिवार्य करता है। लेकिन यह मामला नहीं है - प्रीप्रोसेसिंग के कुछ रूप का उपयोग करके, बहुत से काम से बचा जा सकता है। आमतौर पर उपयोग किए जाने वाले से थोड़ा अधिक स्मार्ट लिंक के साथ, इनमें से कुछ अक्षमताओं को दूर करना संभव है। यह is6.2.3 और discussed6.2.5 में चर्चा की गई है।

चूंकि रिपोर्ट 2006 में लिखी गई थी, इसलिए एक को उम्मीद होगी कि कई सिफारिशों को वर्तमान संकलक में शामिल किया गया होगा, लेकिन शायद ऐसा नहीं है।

जैसा कि आप उल्लेख करते हैं, पहलुओं में सुविधा नहीं हो सकती है write()(लेकिन मैं इसे आँख बंद करके नहीं मानूंगा)। तो क्या सुविधा है? ostringstreamजीसीसी के साथ संकलित आपके कोड पर GProf चलाने से निम्नलिखित ब्रेकडाउन मिलता है:

  • में 44.23% std::basic_streambuf<char>::xsputn(char const*, int)
  • में 34.62% std::ostream::write(char const*, int)
  • में 12.50% main
  • में 6.73% std::ostream::sentry::sentry(std::ostream&)
  • में 0.96% std::string::_M_replace_safe(unsigned int, unsigned int, char const*, unsigned int)
  • में 0.96% std::basic_ostringstream<char>::basic_ostringstream(std::_Ios_Openmode)
  • में 0.00% std::fpos<int>::fpos(long long)

इसलिए समय का बड़ा हिस्सा इसमें बिताया जाता है xsputn, जो अंततः std::copy()कर्सर की स्थिति और बफ़र की बहुत सारी जाँच और अद्यतन के बाद कॉल करता है ( c++\bits\streambuf.tccविवरण के लिए एक नज़र डालें )।

इस पर मेरा कहना है कि आपने सबसे खराब स्थिति पर ध्यान केंद्रित किया है। यदि आपके द्वारा यथोचित बड़े डेटा के साथ काम किया जाता है, तो जो भी चेकिंग की जाती है, वह पूरी तरह से किए गए कुल काम का एक छोटा सा हिस्सा होगा। लेकिन आपका कोड एक बार में चार बाइट्स में डेटा शिफ्ट कर रहा है, और हर बार सभी अतिरिक्त लागतों को वसूल रहा है। स्पष्ट रूप से एक वास्तविक जीवन की स्थिति में ऐसा करने से बचना होगा - विचार करें कि दंड कितना नगण्य होता अगर writeएक इंट पर 1 मी बार के बजाय 1 मीटर की एक सरणी पर बुलाया जाता। और एक वास्तविक जीवन की स्थिति में IOStreams की महत्वपूर्ण विशेषताओं की वास्तव में सराहना होगी, अर्थात् इसकी मेमोरी-सुरक्षित और टाइप-सुरक्षित डिज़ाइन। इस तरह के लाभ एक मूल्य पर आते हैं, और आपने एक परीक्षण लिखा है जो इन लागतों को निष्पादन समय पर हावी बनाता है।


स्वरूपित सम्मिलन / iostreams के निष्कर्षण पर भविष्य के प्रश्न के लिए महान जानकारी की तरह लगता है जो मैं शायद जल्द ही पूछूंगा। लेकिन मैं नहीं मानता कि इसमें कोई पहलू शामिल हैं ostream::write()
बेन वॉइग्ट

4
प्रोफाइलिंग के लिए +1 (यह एक लिनक्स मशीन है जो मुझे लगता है?)। हालांकि, मैं वास्तव में एक समय में चार बाइट्स जोड़ रहा हूं (वास्तव में sizeof i, लेकिन सभी कंपाइलर जिनके साथ मैं 4-बाइट का परीक्षण कर रहा हूं int)। और यह सब मेरे लिए अवास्तविक नहीं लगता है, आपको लगता है कि आप किस आकार में कॉल करते हैं xsputnजैसे कि विशिष्ट कोड में प्रत्येक कॉल में stream << "VAR: " << var.x << ", " << var.y << endl;
बेन Voigt

39
@beldaz: वह "विशिष्ट" कोड उदाहरण जो केवल xsputnपांच बार कॉल करता है वह एक लूप के अंदर बहुत अच्छी तरह से हो सकता है जो एक 10 मिलियन लाइन फ़ाइल लिखता है। बड़े पैमाने पर iostreams में डेटा पास करना मेरे बेंचमार्क कोड की तुलना में वास्तविक जीवन के परिदृश्य से बहुत कम है। मुझे न्यूनतम संख्या में कॉल के साथ बफ़र स्ट्रीम पर क्यों लिखना चाहिए ? अगर मुझे अपनी स्वयं की बफरिंग करनी है, तो वैसे भी iostreams का क्या मतलब है? और द्विआधारी डेटा के साथ, मेरे पास इसे स्वयं को बफर करने का विकल्प है, जब एक पाठ फ़ाइल में लाखों नंबर लिखते हैं, तो थोक विकल्प बस मौजूद नहीं है, मुझे operator <<हर एक को कॉल करना होगा।
बेन वायगट

1
@ बल्डेज: एक अनुमान लगा सकता है कि जब मैं / ओ एक साधारण गणना के साथ हावी होने लगता है। 90 एमबी / एस औसत लेखन दर पर जो कि वर्तमान उपभोक्ता ग्रेड हार्ड डिस्क की विशिष्ट है, 4 एमबी बफर को फ्लश करता है <45ms (थ्रूपुट, विलंबता ओएस लेखन कैश के कारण महत्वहीन है)। यदि आंतरिक लूप को चलाने में बफर भरने में अधिक समय लगता है, तो सीपीयू सीमित कारक होगा। यदि आंतरिक लूप तेजी से चलता है, तो I / O सीमित कारक होगा, या वास्तविक कार्य करने के लिए कम से कम कुछ CPU समय बचा होगा।
बेन Voigt

5
बेशक, इसका मतलब यह नहीं है कि iostreams का उपयोग करना एक धीमी प्रोग्राम का मतलब है। यदि I / O प्रोग्राम का बहुत छोटा हिस्सा है, तो खराब प्रदर्शन के साथ I / O लाइब्रेरी का उपयोग करने से बहुत अधिक प्रभाव नहीं होगा। लेकिन अक्सर बात करने के लिए पर्याप्त नहीं कहा जा रहा है अच्छा प्रदर्शन के रूप में ही नहीं है, और मैं / हे भारी अनुप्रयोगों में, यह बात करता है।
बेन Voigt

27

मैं विजुअल स्टूडियो के उपयोगकर्ताओं को निराश कर रहा हूं, लेकिन उन्हें इस बात पर शर्म नहीं है:

  • दृश्य स्टूडियो कार्यान्वयन में ostream, sentryऑब्जेक्ट (जो मानक द्वारा आवश्यक है) एक महत्वपूर्ण अनुभाग में प्रवेश करता है streambufजो (जो आवश्यक नहीं है) की रक्षा करता है। यह वैकल्पिक प्रतीत नहीं होता है, इसलिए आप एक एकल थ्रेड द्वारा उपयोग की जाने वाली स्थानीय स्ट्रीम के लिए भी थ्रेड सिंक्रोनाइज़ेशन की लागत का भुगतान करते हैं, जिसे सिंक्रोनाइज़ेशन की कोई आवश्यकता नहीं है।

यह कोड को नुकसान पहुँचाता है जो ostringstreamसंदेशों को बहुत गंभीर रूप से प्रारूपित करता है। stringbufसीधे उपयोग करने से बचता है sentry, लेकिन स्वरूपित सम्मिलन ऑपरेटर सीधे काम नहीं कर सकते हैं streambuf। दृश्य C ++ 2010 के लिए, महत्वपूर्ण खंड ostringstream::writeतीन बनाम अंतर्निहित stringbuf::sputnकॉल के एक कारक से धीमा हो रहा है ।

Newlib पर beldaz के प्रोफाइलर डेटा को देखते हुए , यह स्पष्ट है कि gcc sentryइस तरह से कुछ भी पागल नहीं करता है। ostringstream::writeजीसीसी के तहत केवल 50% से अधिक समय लगता है stringbuf::sputn, लेकिन stringbufखुद वीसी ++ की तुलना में बहुत धीमा है। और दोनों अभी भी vector<char>I / O बफरिंग के लिए उपयोग करने के लिए बहुत प्रतिकूल तुलना करते हैं , हालांकि VC ++ के तहत समान मार्जिन द्वारा नहीं।


क्या यह जानकारी अभी तक है? AFAIK, C ++ 11 जीसीसी के साथ लागू किया गया कार्यान्वयन इस 'पागल' लॉक को निष्पादित करता है। निश्चित रूप से, VS2010 अभी भी यह करता है। क्या कोई भी इस व्यवहार को स्पष्ट कर सकता है और यदि 'जिसकी आवश्यकता नहीं है' अभी भी C ++ 11 में है?
मलोत्स्क

2
@mloskot: मुझे कोई थ्रेड-सुरक्षा आवश्यकता नहीं है sentry... "क्लास संतरी एक वर्ग को परिभाषित करता है जो अपवाद सुरक्षित उपसर्ग और प्रत्यय संचालन करने के लिए जिम्मेदार है।" और एक नोट "संतरी निर्माता और विध्वंसक भी अतिरिक्त कार्यान्वयन-निर्भर संचालन कर सकते हैं।" आप "आप जो उपयोग नहीं करते हैं, उसके लिए भुगतान नहीं करते हैं" के C ++ सिद्धांत से कोई भी भुगतान कर सकता है कि C ++ समिति कभी भी ऐसी बेकार आवश्यकता को स्वीकार नहीं करेगी। लेकिन iostream धागा सुरक्षा के बारे में एक प्रश्न पूछने के लिए स्वतंत्र महसूस करें।
बेन वोइगट

8

समस्या जो आप देख रहे हैं वह लिखने के लिए प्रत्येक कॉल के चारों ओर ओवरहेड में है ()। अमूर्तता का प्रत्येक स्तर जो आप जोड़ते हैं (char [] -> वेक्टर -> स्ट्रिंग -> ओस्ट्रिंगस्ट्रीम) कुछ और फ़ंक्शन कॉल / रिटर्न और अन्य हाउसकीपिंग गफ़ - जो कि अगर आप इसे एक लाख बार कहते हैं - कहते हैं।

मैंने एक बार में दस इनट्स लिखने के लिए ideone पर दो उदाहरणों को संशोधित किया। ऑस्ट्रिंगस्ट्रीम समय 53 से 6 एमएस (लगभग 10 एक्स सुधार) से गया, जबकि चार लूप में सुधार हुआ (3.7 से 1.5) - उपयोगी, लेकिन केवल दो के एक कारक द्वारा।

यदि आप प्रदर्शन के बारे में चिंतित हैं तो आपको नौकरी के लिए सही उपकरण चुनने की आवश्यकता है। ostringstream उपयोगी और लचीला है, लेकिन इसका उपयोग करने के तरीके के लिए एक दंड है। चार [] कठिन काम है, लेकिन प्रदर्शन लाभ बहुत अच्छा हो सकता है (याद रखें कि जीसीसी शायद आपके लिए भी ज्ञापन को अच्छी तरह से इनलाइन करेगा)।

संक्षेप में, ओस्ट्रिंगस्ट्रीम टूटा नहीं है, लेकिन धातु के जितना करीब आप तेजी से आपका कोड चलाएंगे। असेंबलर में अभी भी कुछ लोगों के लिए फायदे हैं।


8
क्या ostringstream::write()करना है कि vector::push_back()नहीं करता है? यदि कुछ भी हो, तो इसे चार व्यक्तिगत तत्वों के बजाय एक ब्लॉक सौंपने के बाद से तेज होना चाहिए। यदि कोई अतिरिक्त सुविधाएँ प्रदान किए बिना ostringstreamधीमी std::vectorहै, तो हाँ मैं उस टूटे हुए को कॉल करूंगा।
बेन वोइगट

1
@ बीन वायगट: इसके विपरीत, इसके कुछ वेक्टर को ऐसा करना पड़ता है कि ओस्ट्रिंगस्ट्रीम DOESN'T को ऐसा करना पड़ता है जो वेक्टर को इस मामले में और अधिक उत्कृष्ट बनाता है। वेक्टर को स्मृति में सन्निहित होने की गारंटी दी जाती है, जबकि ओस्ट्रिंगस्ट्रीम नहीं है। वेक्टर उन वर्गों में से एक है जिसे प्रदर्शन करने के लिए डिज़ाइन किया गया है, जबकि ओस्ट्रिंगस्ट्रीम नहीं है।
ड्रैगॉन्टामेर

2
@Ben Voigt: stringbufसीधे उपयोग करने से सभी फ़ंक्शन कॉल को हटाने वाला नहीं है क्योंकि stringbufसार्वजनिक इंटरफ़ेस में बेस क्लास में सार्वजनिक गैर-वर्चुअल फ़ंक्शंस होते हैं जो तब व्युत्पन्न वर्ग में संरक्षित वर्चुअल फ़ंक्शन को भेजते हैं।
CB बेली

2
@Charles: किसी भी सभ्य कंपाइलर पर, चूंकि सार्वजनिक फ़ंक्शन कॉल को एक संदर्भ में इनलाइन मिल जाएगा, जहां डायनामिक प्रकार को कंपाइलर के लिए जाना जाता है, यह उन कॉलों को अप्रत्यक्ष और इनलाइन को भी हटा सकता है।
बेन Voigt

6
@Roddy: मुझे सोचना चाहिए कि यह सब इनलाइन टेम्पलेट कोड है, जो हर संकलन इकाई में दिखाई देता है। लेकिन मुझे लगता है कि कार्यान्वयन से भिन्न हो सकते हैं। कुछ के लिए मैं चर्चा के तहत कॉल की उम्मीद करूंगा, सार्वजनिक sputnफ़ंक्शन जो वर्चुअल संरक्षित को कॉल करता है xsputn, इनलाइन हो। यहां तक ​​कि अगर xsputnइनबिल्ट नहीं है, तो संकलक, इनलाइन करते समय sputn, xsputnआवश्यक ओवरराइड को निर्धारित कर सकता है और वाइबेटर से गुजरे बिना एक सीधा कॉल उत्पन्न कर सकता है।
बेन वोइगट

1

बेहतर प्रदर्शन प्राप्त करने के लिए आपको यह समझना होगा कि आप किस कंटेनर का उपयोग कर रहे हैं। आपके चार [] सरणी उदाहरण में, आवश्यक आकार का सरणी अग्रिम में आवंटित किया गया है। अपने वेक्टर और ऑस्ट्रिंगस्ट्रीम उदाहरण में आप ऑब्जेक्ट्स को बार-बार आवंटित करने और वास्तविक बनाने के लिए मजबूर कर रहे हैं और संभवतः ऑब्जेक्ट को बढ़ने पर डेटा को कई बार कॉपी करते हैं।

एसटीडी के साथ :: वेक्टर यह आसानी से वेक्टर आकार को अंतिम आकार के रूप में निर्धारित करके हल किया जाता है जैसा कि आपने चार सरणी में किया था; इसके बजाय आप गलत तरीके से प्रदर्शन को शून्य का आकार देकर अपंग करते हैं! यह शायद ही एक उचित तुलना है।

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

वेक्टर और ओस्ट्रिंगस्ट्रीम के मामले में आपको बफर ओवररन से सुरक्षा मिलती है, आपको वह चार सरणी के साथ नहीं मिलती है, और वह सुरक्षा मुफ्त में नहीं आती है।


1
आवंटन आस्ट्रिया के लिए मुद्दा नहीं लगता है। वह बाद में पुनरावृत्तियों के लिए शून्य पर वापस जाना चाहता है। कोई छंटनी नहीं। इसके अलावा मैंने कोशिश की ostringstream.str.reserve(4000000)और इससे कोई फर्क नहीं पड़ा।
रोडी

मैं के साथ लगता है ostringstream, तो आप कर सकते थे एक डमी स्ट्रिंग में पारित करके "आरक्षित", अर्थात्: ostringstream str(string(1000000 * sizeof(int), '\0'));के साथ vector, resizeकिसी भी स्थान पुनःआवंटन नहीं करता है, यह केवल फैलता है अगर यह की जरूरत है।
निम

1
"वेक्टर .. बफर ओवररन से सुरक्षा"। एक आम ग़लतफ़हमी - vector[]ऑपरेटर आमतौर पर डिफ़ॉल्ट रूप से सीमा त्रुटियों के लिए जाँच नहीं किया जाता है। vector.at()हालाँकि है।
रोडी

2
vector<T>::resize(0)आमतौर पर स्मृति को फिर से
विभाजित

2
@ राशि: उपयोग नहीं operator[], लेकिन push_back()(वैसे back_inserter), जो निश्चित रूप से अतिप्रवाह के लिए परीक्षण करता है। एक और संस्करण जोड़ा गया जो उपयोग नहीं करता है push_back
बेन Voigt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.