2009-09-01 14 views
20

एक ही प्रोग्राम प्रदान करने के बाद जो यादृच्छिक जेनरेट की गई इनपुट फ़ाइल पढ़ता है और उसी स्ट्रिंग को इको करता है जो इसे आउटपुट में पढ़ता है। केवल अंतर यह है कि एक तरफ मैं लिनक्स सिस्को से पढ़ने और लिखने के तरीकों को प्रदान कर रहा हूं, और दूसरी तरफ मैं फ्रेड/फेराइट का उपयोग कर रहा हूं।क्यों fwrite libc फ़ंक्शन syscall लेखन फ़ंक्शन से तेज़ है?

आकार में 10 एमबी के इनपुट के साथ मेरे आवेदन को समयबद्ध करना और इसे/dev/null पर प्रतिबिंबित करना, और यह सुनिश्चित करना कि फ़ाइल कैश नहीं है, मुझे पता चला है कि बहुत छोटे बफर का उपयोग करते समय libc की fwrite एक बड़े पैमाने पर तेज़ है (मामले में 1 बाइट)।

यहाँ, समय पर अपने उत्पादन है fwrite का उपयोग कर:

real 0m0.948s 
user 0m0.780s 
sys  0m0.012s 

और syscall लिखने का उपयोग कर:

real 0m8.607s 
user 0m0.972s 
sys  0m7.624s 

केवल संभावना है कि मैं के बारे में सोच सकता है कि आंतरिक रूप से libc पहले से ही बफरिंग है मेरी इनपुट ... दुर्भाग्य से मुझे वेब के चारों ओर इतनी सारी जानकारी नहीं मिल सका, तो यहां गुरु यहां मेरी मदद कर सकते हैं।

+4

"आंतरिक रूप से libc पहले से ही मेरे इनपुट को बफर कर रहा है"। यह वही है जो यह कर रहा है। यदि आप चाहें तो शायद आप libc के लिए स्रोत कोड भी पढ़ सकते हैं, और देख सकते हैं कि यह वास्तव में कैसा चल रहा है। – kquinn

उत्तर

29

आकार में 10 एमबी एक इनपुट के साथ अपने आवेदन समय और /dev/बातिल करने के लिए इसे गूंज, और सुनिश्चित करें में फ़ाइल कैश नहीं कर रही है, मैंने पाया कि libc के frwite एक बड़ी से तेजी से होता है स्केल बहुत छोटे बफर का उपयोग करके ( मामले में 1 बाइट)।

fwrite स्ट्रीम पर काम करता है, जो buffered हैं। इसलिए बहुत से छोटे बफर तेजी से होंगे क्योंकि बफर भरने तक यह महंगा सिस्टम कॉल नहीं चलाएगा (या आप इसे फ्लश करते हैं या स्ट्रीम बंद करते हैं)। दूसरी तरफ, write पर भेजे जाने वाले छोटे बफर प्रत्येक बफर के लिए एक महंगा सिस्टम कॉल चलाएंगे - यही वह जगह है जहां आप गति खो रहे हैं। 1024 बाइट स्ट्रीम बफर के साथ, और 1 बाइट बफर लिखने के साथ, आप 1024 write प्रत्येक किलोबाइट के लिए कॉल कर रहे हैं, 1024 fwrite कॉल write में बदलते हुए - अंतर देखें?

बड़े बफर के लिए अंतर छोटा होगा, क्योंकि कम बफरिंग होगी, और इसलिए fwrite और write के बीच सिस्टम कॉल की एक अधिक संगत संख्या होगी।

दूसरे शब्दों में, fwrite(3) केवल एक लाइब्रेरी दिनचर्या है जो भागों में आउटपुट एकत्र करती है, और फिर write(2) पर कॉल करती है। अब, write(2), सिस्टम कॉल है जो कर्नेल में जाल है। यही वह जगह है जहां I/O वास्तव में होता है। कर्नेल में बस कॉल करने के लिए कुछ ओवरहेड है, और फिर वास्तव में कुछ लिखने में लगने वाला समय होता है। यदि आप बड़े बफर का उपयोग करते हैं, तो आप पाएंगे कि write(2) तेज है क्योंकि इसे अंततः वैसे भी बुलाया जाना चाहिए, और यदि आप प्रति fwrite में एक या अधिक बार लिख रहे हैं तो fwrite buffering ओवरहेड बस इतना है: अधिक ओवरहेड।

यदि आप इसके बारे में अधिक पढ़ना चाहते हैं, तो आप this document पर एक नज़र डाल सकते हैं, जो मानक I/O धाराओं को बताता है।

10

आप setbuf() फ़ंक्शन के साथ बफरिंग भी अक्षम कर सकते हैं। जब बफरिंग अक्षम हो जाती है, तो fwrite() धीमा नहीं होने पर लिखने के रूप में धीमा होगा()।इस विषय पर

अधिक जानकारी वहाँ पाया जा सकता है: http://www.gnu.org/s/libc/manual/html_node/Controlling-Buffering.html

14

write (2) मौलिक गिरी ऑपरेशन है।

fwrite (3) एक लाइब्रेरी फ़ंक्शन है जो write (2) के शीर्ष पर बफरिंग जोड़ता है।

छोटे (उदाहरण के लिए, लाइन-एट-ए-टाइम) बाइट गणना के लिए, fwrite (3) तेज है, केवल कर्नेल कॉल करने के लिए ओवरहेड की वजह से।

बड़े (ब्लॉक I/O) बाइट गणना के लिए, write (2) तेज़ है, क्योंकि यह बफरिंग से परेशान नहीं है और आपको कर्नेल को दोनों मामलों में कॉल करना होगा।

यदि आप cp (1) पर स्रोत देखते हैं, तो आपको कोई बफरिंग दिखाई नहीं देगी।

अंत में, एक अंतिम विचार है: आईएसओ सी बनाम Posix। fwrite जैसे buffered लाइब्रेरी फ़ंक्शंस आईएसओ सी में निर्दिष्ट हैं जबकि कर्नेल कॉल write पॉज़िक्स हैं। हालांकि कई प्रणालियां पॉजिक्स-संगतता का दावा करती हैं, खासकर सरकारी अनुबंधों के लिए अर्हता प्राप्त करने का प्रयास करते समय, यह यूनिक्स जैसी प्रणालियों के लिए विशिष्ट है। तो, buffered ops अधिक पोर्टेबल हैं। नतीजतन, एक लिनक्स cp निश्चित रूप से write का उपयोग करेगा, लेकिन एक सी प्रोग्राम जो क्रॉस-प्लेटफॉर्म पर काम करना है उसे fwrite का उपयोग करना पड़ सकता है।

+0

मैंने हाल ही में एक साक्षात्कार लिया था और मैंने अंतर बी/डब्ल्यू लिखने और fwrite के बारे में एक ही तर्क दिया था और मुझे जवाब मिला था, "आप इस अंतर के बारे में ज्ञान पूरी तरह से फर्जी है" !! साक्षात्कारकर्ता मेरे लिए बहुत अहंकारी लग रहा था। फिर भी, मैं सिर्फ पुष्टि करना चाहता था, अगर ग्लिब और कॉल को सीधे कर्नेल में किए गए कॉल के बीच कोई अन्य अंतर है? –

+0

@ पीके, मैंने अपना जवाब अपडेट कर दिया है ... – DigitalRoss

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