2012-06-26 17 views
10

निम्नलिखित परीक्षण करने के बाद:लिखें या प्रिंटफ, जो तेज़ है?

for(i = 0; i < 3000000; i++) { 
    printf("Test string\n"); 
} 

for(i = 0; i < 3000000; i++) { 
    write(STDOUT_FILENO, "Test string\n", strlen("Test string\n")); 
} 

यह पता चला है कि कॉल 3 सेकंड तक महायोग ले printf करने के लिए, कॉल एक whopping 46 सेकंड का समय लिखने के लिए है। कैसे, सभी फैंसी स्वरूपण जादू के साथ printf करता है, और तथ्य यह है कि printf स्वयं write पर कॉल करता है, क्या यह संभव है? क्या ऐसा कुछ है जो मुझे याद आ रहा है?

किसी भी और सभी विचारों और इनपुट की सराहना की जाती है।

+0

यह आपके सिस्टम पर निर्भर करता है – JMBise

+3

printf बफरिंग करता है। –

+9

वास्तव में? आप हर बार स्ट्रिंग लम्बाई की गणना कर रहे हैं और फिर उस समय के हिस्से के रूप में माप रहे हैं? –

उत्तर

22

कैसे ... तथ्य यह है कि प्रिंटफ स्वयं लिखता है, क्या यह संभव है? क्या ऐसा कुछ है जो मुझे याद आ रहा है?

हां, ऐसा कुछ है जिसे आप याद कर रहे हैं। printf आवश्यक नहीं है writeहर बार पर कॉल करें। इसके बजाय, printf इसके आउटपुट को बफर करता है। यही है, यह अक्सर मेमोरी बफर में अपना परिणाम संग्रहीत करता है, केवल बफर भरने पर, या कुछ अन्य स्थितियों पर write पर कॉल करता है।

write एक काफी महंगा कॉल, बहुत printf के बफर में डेटा की प्रतिलिपि है, तो write कॉल की संख्या एक शुद्ध प्रदर्शन जीत को कम करने प्रदान करता है से ज्यादा महंगा है।

अपने stdout एक टर्मिनल डिवाइस को निर्देश दिया जाता है, तो printf कॉल write हर बार यह एक \n देखता है - आपके मामले में, हर बार यह कहा जाता है। यदि आपका स्टडआउट किसी फ़ाइल (या /dev/null) पर निर्देशित किया गया है, तो printf कॉल केवल तब लिखते हैं जब उसका आंतरिक बफर भरा होता है।

जाना चाहिए कि आप अपने उत्पादन रीडायरेक्ट कर रहे हैं, और कहा कि printf के आंतरिक बफर 4Kbytes है, तो पहले पाश का आह्वान write 3000000/(4096/12) == 8780 बार। आपका दूसरा पाश, हालांकि, write 3000000 बार आमंत्रित करता है।

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

मुझे उम्मीद है कि आपका पहला पाश दूसरे की तुलना में बहुत तेज हो जाएगा।

+1

यह सबकुछ ठीक से बताता है। धन्यवाद! डेटा आकार के बारे में आपकी टिप्पणी के बारे में ...मूल डेटा को केवल इसलिए पढ़ने की आवश्यकता क्यों नहीं है क्योंकि यह इस क्षेत्र में पूरी तरह से फिट बैठता है? क्या लिखने के कॉल को अभी भी उस डेटा को जानने की आवश्यकता नहीं है जिसे लिखे जाने की आवश्यकता है? – Ataraxia

4

आप सेब के लिए सेब की तुलना नहीं कर रहे हैं, क्योंकि write रन के साथ पाश strlen3000000 बार, printf कि कोई भी कार्य नहीं कर रहा है, जबकि; यह या तो कोई स्वरूपण नहीं करता है, इसलिए "फैंसी स्वरूपण जादू" शायद ही लागू होता है।

size_t len = strlen("Test string\n"); 
for(i = 0; i < 3000000; i++) { 
    write(STDOUT_FILENO, "Test string\n", len); 
} 

एक और महत्वपूर्ण अंतर है कि printf flushes हर बार जब आप \n गुजरती हैं, जबकि write नहीं करता है। अपने बेंचमार्क को और अधिक न्यायसंगत बनाने के लिए आपको दोनों स्ट्रिंग्स से \n हटा देना चाहिए।

+3

मेरे सिस्टम पर, gcc-4.5.1 संकलन के समय भी संकलन के समय 'strlen' का मूल्यांकन करता है। फ्लशिंग/बफरिंग फर्क पड़ता है जो अंतर बनाता है। –

+0

@DanielFischer धन्यवाद! यह जानना अच्छा लगता है कि 'gcc' स्थिरता में' strlen' अभिव्यक्ति को फोल्ड करने के लिए पर्याप्त स्मार्ट है। – dasblinkenlight

+2

'printf' ** ** प्रत्येक फ़ाइल पर फ्लश नहीं होता है \ n' अगर आउटपुट को फ़ाइल पर रीडायरेक्ट किया जाता है। साथ ही, यह कहना अधिक सटीक है कि 'लिखना' हर बार फ्लश करता है, सामग्री के बिना, बिना किसी संदर्भ में, इस संदर्भ में "फ्लश" का अर्थ केवल "कॉल 'लिखना है।" –

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