FileInputStream का उपयोग करते समय आप आदर्श बफर आकार कैसे निर्धारित करते हैं?


156

मेरे पास एक ऐसा तरीका है जो एक फ़ाइल से एक संदेशडॉगस्ट (एक हैश) बनाता है, और मुझे बहुत सारी फ़ाइलों (> = 100,000) के लिए ऐसा करने की आवश्यकता है। प्रदर्शन को अधिकतम करने के लिए मुझे फ़ाइलों से पढ़ने के लिए उपयोग किए जाने वाले बफर को कितना बड़ा बनाना चाहिए?

ज्यादातर लोग मूल कोड से परिचित हैं (जो मैं यहाँ सिर्फ मामले में दोहराऊंगा):

MessageDigest md = MessageDigest.getInstance( "SHA" );
FileInputStream ios = new FileInputStream( "myfile.bmp" );
byte[] buffer = new byte[4 * 1024]; // what should this value be?
int read = 0;
while( ( read = ios.read( buffer ) ) > 0 )
    md.update( buffer, 0, read );
ios.close();
md.digest();

थ्रूपुट को अधिकतम करने के लिए बफर का आदर्श आकार क्या है? मुझे पता है कि यह सिस्टम पर निर्भर है, और मुझे पूरा यकीन है कि इसका ओएस, फाइलसिस्टम और एचडीडी निर्भर है, और शायद मिश्रण में अन्य हार्डवेयर / सॉफ्टवेयर भी हैं।

(मुझे यह बताना चाहिए कि मैं जावा में कुछ नया हूं, इसलिए यह सिर्फ कुछ जावा एपीआई कॉल हो सकता है जिनके बारे में मुझे नहीं पता है।)

संपादित करें: मैं समय से पहले नहीं जानता कि किस प्रकार के सिस्टम का उपयोग किया जाएगा, इसलिए मैं पूरी तरह से ग्रहण नहीं कर सकता। (मैं उस कारण से जावा का उपयोग कर रहा हूं।)

संपादित करें: ऊपर दिया गया कोड चीजों को याद कर रहा है जैसे कि पोस्ट को छोटा करने के लिए प्रयास करें

जवाबों:


213

इष्टतम बफर आकार कई चीजों से संबंधित है: फाइल सिस्टम ब्लॉक आकार, सीपीयू कैश आकार और कैश विलंबता।

अधिकांश फ़ाइल सिस्टम को 4096 या 8192 के ब्लॉक आकारों का उपयोग करने के लिए कॉन्फ़िगर किया गया है। सिद्धांत रूप में, यदि आप अपने बफर आकार को कॉन्फ़िगर करते हैं तो आप डिस्क ब्लॉक से कुछ बाइट्स पढ़ रहे हैं, फ़ाइल सिस्टम के साथ संचालन बेहद अक्षम हो सकता है (अर्थात यदि आप एक समय में 4100 बाइट्स पढ़ने के लिए अपने बफर को कॉन्फ़िगर किया, प्रत्येक रीड को फाइल सिस्टम द्वारा 2 ब्लॉक रीड की आवश्यकता होगी)। यदि ब्लॉक पहले से कैश में हैं, तो आप रैम की कीमत का भुगतान करते हैं -> L3 / L2 कैश विलंबता। यदि आप अशुभ हैं और ब्लॉक अभी तक कैश में नहीं हैं, तो आप डिस्क की कीमत का भुगतान करते हैं-> RAM विलंबता भी।

यही कारण है कि आप अधिकांश बफ़र्स को 2 की शक्ति के रूप में और आमतौर पर डिस्क ब्लॉक आकार से बड़े (या बराबर) देखते हैं। इसका मतलब है कि आपकी एक स्ट्रीम पढ़ता है जिसके परिणामस्वरूप कई डिस्क ब्लॉक रीड हो सकते हैं - लेकिन वे रीड हमेशा एक पूर्ण ब्लॉक का उपयोग करेंगे - कोई व्यर्थ नहीं पढ़ता है।

अब, यह एक विशिष्ट स्ट्रीमिंग परिदृश्य में बहुत थोड़ा ऑफसेट है क्योंकि डिस्क से पढ़ा जाने वाला ब्लॉक अभी भी मेमोरी में हो रहा है जब आप अगली रीड मारते हैं (हम अनुक्रमिक रीड यहां कर रहे हैं, आखिरकार) - तो आप हवा अगली रीड पर RAM -> L3 / L2 कैश विलंबता मूल्य का भुगतान करना, लेकिन डिस्क-> RAM विलंबता नहीं। परिमाण के क्रम के संदर्भ में, डिस्क-> RAM विलंबता इतनी धीमी है कि यह किसी भी अन्य विलंबता से बहुत अधिक झूल जाती है, जिससे आप निपट सकते हैं।

इसलिए, मुझे संदेह है कि यदि आपने अलग-अलग कैश आकार (यह खुद नहीं किया है) के साथ एक परीक्षण चलाया, तो आप संभवतः फ़ाइल सिस्टम ब्लॉक के आकार तक कैश आकार का एक बड़ा प्रभाव पाएंगे। उसके ऊपर, मुझे संदेह है कि चीजें बहुत जल्दी समाप्त हो जाएंगी।

यहां एक टन की स्थिति और अपवाद हैं - सिस्टम की जटिलताएं वास्तव में काफी चौंका देने वाली हैं (बस L3 पर एक हैंडल प्राप्त करना है - L2 कैश ट्रांसफर दिमाग का जटिल है, और यह हर सीपीयू प्रकार के साथ बदलता है)।

यह 'वास्तविक दुनिया' का जवाब देता है: यदि आपका ऐप 99% बाहर है, तो कैश आकार को 8192 पर सेट करें और आगे बढ़ें (और भी बेहतर, प्रदर्शन पर इनकैप्सुलेशन चुनें और विवरण छिपाने के लिए BufferedInputStream का उपयोग करें)। यदि आप 1% ऐप्स में हैं जो डिस्क थ्रूपुट पर अत्यधिक निर्भर हैं, तो अपने कार्यान्वयन को तैयार करें ताकि आप विभिन्न डिस्क इंटरैक्शन रणनीतियों को स्वैप कर सकें, और अपने उपयोगकर्ताओं को परीक्षण और अनुकूलन (या कुछ के साथ आने) की अनुमति देने के लिए नॉब्स और डायल प्रदान कर सकें। आत्म अनुकूलन प्रणाली)।


3
मैंने दोनों के लिए अपने एंड्रॉइड ऐप के लिए एक मोबाइल फोन (Nexus 5X) पर कुछ बैनमार्किंग की: छोटी फाइलें (3,5Mb) और बड़ी फाइलें (175 एमबी)। और पता चला कि सुनहरा आकार 524288 लंबाई का बाइट [] होगा। यदि आप फ़ाइल के आकार के आधार पर छोटे बफर 4Kb और बड़े बफर 524Kb के बीच स्विच करते हैं, तो आप 10-20ms जीत सकते हैं, लेकिन यह इसके लायक नहीं है। तो मेरे मामले में 524 Kb सबसे अच्छा विकल्प था।
किरिल कर्मज़ीन

19

हां, यह शायद विभिन्न चीजों पर निर्भर है - लेकिन मुझे संदेह है कि इससे बहुत फर्क पड़ेगा। मैं स्मृति उपयोग और प्रदर्शन के बीच एक अच्छे संतुलन के रूप में 16K या 32K का विकल्प चुनता हूं।

ध्यान दें कि आपके पास कोड में एक कोशिश / अंत में ब्लॉक होना चाहिए यह सुनिश्चित करने के लिए कि धारा बंद है भले ही एक अपवाद फेंक दिया गया हो।


मैंने कोशिश के बारे में पोस्ट संपादित की..कैच। मेरे वास्तविक कोड में मेरे पास एक है, लेकिन मैंने पोस्ट को छोटा करने के लिए इसे छोड़ दिया।
ARKBAN

1
अगर हम इसके लिए एक निश्चित आकार को परिभाषित करना चाहते हैं, तो कौन सा आकार बेहतर है? 4k, 16k या 32k?
बैटलटेड

2
@MohammadrezaPanahi: कृपया बेजर उपयोगकर्ताओं के लिए टिप्पणियों का उपयोग न करें। आपने दूसरी टिप्पणी से एक घंटे पहले कम प्रतीक्षा की । कृपया याद रखें कि उपयोगकर्ता आसानी से सो सकते हैं, या बैठकों में, या मूल रूप से अन्य चीजों के साथ व्यस्त हो सकते हैं और टिप्पणियों का जवाब देने के लिए शून्य दायित्व हैं। लेकिन आपके प्रश्न का उत्तर देने के लिए: यह पूरी तरह से संदर्भ पर निर्भर करता है। यदि आप बहुत स्मृति-बाधित प्रणाली पर चल रहे हैं, तो आप शायद एक छोटा बफर चाहते हैं। यदि आप एक बड़ी प्रणाली पर चल रहे हैं, तो एक बड़े बफर के उपयोग से रीड कॉल की संख्या कम हो जाएगी। केविन डे का जवाब बहुत अच्छा है।
जॉन स्कीट

7

ज्यादातर मामलों में, यह वास्तव में इतना मायने नहीं रखता है। बस एक अच्छा आकार चुनें जैसे कि 4K या 16K और इसके साथ छड़ी। यदि आप सकारात्मक हैं कि आपके आवेदन में यह अड़चन है, तो आपको इष्टतम बफर आकार खोजने के लिए प्रोफाइलिंग शुरू करनी चाहिए। यदि आप एक आकार चुनते हैं जो बहुत छोटा है, तो आप अतिरिक्त I / O संचालन और अतिरिक्त फ़ंक्शन कॉल करने में समय बर्बाद करेंगे। यदि आप एक आकार चुनते हैं जो बहुत बड़ा है, तो आपको बहुत सारे कैशे छूटने लगेंगे, जो वास्तव में आपको धीमा कर देंगे। अपने L2 कैश आकार से बड़े बफर का उपयोग न करें।


4

आदर्श मामले में फ़ाइल को एक रीड ऑपरेशन में पढ़ने के लिए हमारे पास पर्याप्त मेमोरी होनी चाहिए। यह सबसे अच्छा प्रदर्शन होगा क्योंकि हम सिस्टम को फाइल सिस्टम, आवंटन इकाइयों और एचडीडी का प्रबंधन करने देंगे। व्यवहार में आप पहले से फ़ाइल आकार जानने के लिए भाग्यशाली हैं, बस 4K तक गोलाकार फ़ाइल आकार का उपयोग करें (एफएसआर पर डिफ़ॉल्ट आवंटन इकाई)। और सबसे अच्छा: कई विकल्पों का परीक्षण करने के लिए एक बेंचमार्क बनाएं।


क्या आपका मतलब है कि फ़ाइल में पढ़ने और लिखने के लिए सबसे अच्छा बफर आकार 4k है?
BattleTested

4

आप बफ़रडस्ट्रीम / पाठकों का उपयोग कर सकते हैं और फिर उनके बफर आकारों का उपयोग कर सकते हैं।

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


4

जावा NIO के FileChannel और MappedByteBuffer का उपयोग करके फ़ाइलों को पढ़ना एक समाधान में सबसे अधिक संभावना होगा, जो कि FileInputStream को शामिल करने वाले किसी भी समाधान की तुलना में बहुत तेज़ होगा। मूल रूप से, मेमोरी-मैप बड़ी फाइलें, और छोटे लोगों के लिए प्रत्यक्ष बफ़र्स का उपयोग करें।


4

BufferedInputStream के स्रोत में आप पाएंगे: निजी स्थिर int DEFAULT_BUFFER_SIZE = 8192;
इसलिए आपके लिए उस डिफ़ॉल्ट मान का उपयोग करना ठीक है।
लेकिन अगर आप कुछ और जानकारी का पता लगा सकते हैं तो आपको अधिक मूल्यवान जवाब मिलेंगे।
उदाहरण के लिए, आपके विज्ञापन शायद 1454 बाइट्स के बफर को प्राथमिकता देते हैं, क्योंकि टीसीपी / आईपी का पेलोड। डिस्क के लिए, आप अपने डिस्क के ब्लॉक आकार से मेल खाने वाले मान का उपयोग कर सकते हैं।


1

जैसा कि पहले से ही अन्य उत्तरों में बताया गया है, बफ़रड इनपुटस्ट्रीम का उपयोग करें।

उसके बाद, मुझे लगता है कि बफर आकार वास्तव में मायने नहीं रखता है। या तो कार्यक्रम I / O बाध्य है, और BIS डिफ़ॉल्ट पर बफर आकार बढ़ रहा है, प्रदर्शन पर कोई बड़ा प्रभाव नहीं डालेगा।

या प्रोग्राम MessageDigest.update () के अंदर सीपीयू बाध्य है, और अधिकांश समय एप्लिकेशन कोड में खर्च नहीं किया जाता है, इसलिए इसे ट्विक करने से मदद नहीं मिलेगी।

(हम्म ... कई कोर के साथ, धागे मदद कर सकते हैं।)


0

1024 विभिन्न प्रकार की परिस्थितियों के लिए उपयुक्त है, हालांकि व्यवहार में आप बड़े या छोटे बफर आकार के साथ बेहतर प्रदर्शन देख सकते हैं।

यह फ़ाइल सिस्टम ब्लॉक आकार और सीपीयू हार्डवेयर सहित कई कारकों पर निर्भर करेगा।

बफर आकार के लिए 2 की शक्ति का चयन करना भी सामान्य है, क्योंकि अधिकांश अंतर्निहित हार्डवेयर फ़्लो ब्लॉक और कैश आकार के साथ संरचित होते हैं, जो कि 2 की शक्ति होती है। बफर वर्ग आपको कंस्ट्रक्टर में बफर आकार निर्दिष्ट करने की अनुमति देता है। यदि कोई भी प्रदान नहीं किया जाता है, तो वे डिफ़ॉल्ट मान का उपयोग करते हैं, जो कि अधिकांश जेवीएम में 2 की शक्ति है।

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.