2012-01-03 3 views
37

मेरे पास एक मॉड्यूल है जो डिस्क पर पढ़ने, प्रसंस्करण और बाइट लिखने के लिए ज़िम्मेदार है। बाइट यूडीपी में आते हैं और, अलग-अलग डेटाग्राम इकट्ठे होने के बाद, अंतिम बाइट सरणी जो संसाधित हो जाती है और डिस्क पर लिखी जाती है, आमतौर पर 200 बाइट्स और 500,000 बाइट्स के बीच होती है। कभी-कभी, बाइट एरे होंगे कि, असेंबली के बाद, 500,000 बाइट से अधिक हैं, लेकिन ये अपेक्षाकृत दुर्लभ हैं।बुफर्डऑटपुटस्ट्रीम के साथ फ़ाइलऑटपुटस्ट्रीम को लपेटने के किस बिंदु पर प्रदर्शन के संदर्भ में, समझ में आता है?

मैं वर्तमान में FileOutputStream के write(byte\[\]) method का उपयोग कर रहा हूं। मैं the constructor that accepts a buffer size as a parameter का उपयोग कर BufferedOutputStream में FileOutputStream को लपेटने के साथ भी प्रयोग कर रहा हूं।

ऐसा प्रतीत होता है कि BufferedOutputStream का उपयोग थोड़ा बेहतर प्रदर्शन की ओर बढ़ रहा है, लेकिन मैंने केवल अलग-अलग बफर आकारों के साथ प्रयोग करना शुरू कर दिया है। मेरे पास काम करने के लिए नमूना डेटा का एक सीमित सेट है (नमूना रन से दो डेटा सेट जो मैं अपने आवेदन के माध्यम से पाइप कर सकता हूं)। क्या कोई सामान्य नियम-थंब है कि मैं डिस्क लिखने को कम करने के लिए इष्टतम बफर आकारों की गणना करने और डिस्क लिखने के प्रदर्शन को अधिकतम करने के लिए आवेदन करने में सक्षम हो सकता हूं, जो जानकारी मैं जानता हूं कि मैं जो डेटा लिख ​​रहा हूं उसके बारे में मुझे पता है?

उत्तर

28

BufferedOutputStream मदद करता है जब लेखन बफर आकार से छोटे होते हैं उदा। 8 केबी बड़े लिखने के लिए यह मदद नहीं करता है और न ही इससे इसे और भी बदतर बना देता है। यदि आपके सभी लिखने वाले बफर आकार से बड़े हैं या आप प्रत्येक लिखने के बाद हमेशा फ्लश() करते हैं, तो मैं एक बफर का उपयोग नहीं करता। हालांकि यदि आपके लिखने का एक अच्छा हिस्सा कम है तो बफर आकार और आप हर बार फ्लश() का उपयोग नहीं करते हैं, इसके लायक है।

आप बफर आकार को 32 केबी तक बढ़ा सकते हैं या इससे बड़ा आपको मामूली सुधार देता है, या इससे भी बदतर हो जाता है। YMMV


आप BufferedOutputStream.write के लिए कोड उपयोगी

/** 
* Writes <code>len</code> bytes from the specified byte array 
* starting at offset <code>off</code> to this buffered output stream. 
* 
* <p> Ordinarily this method stores bytes from the given array into this 
* stream's buffer, flushing the buffer to the underlying output stream as 
* needed. If the requested length is at least as large as this stream's 
* buffer, however, then this method will flush the buffer and write the 
* bytes directly to the underlying output stream. Thus redundant 
* <code>BufferedOutputStream</code>s will not copy data unnecessarily. 
* 
* @param  b  the data. 
* @param  off the start offset in the data. 
* @param  len the number of bytes to write. 
* @exception IOException if an I/O error occurs. 
*/ 
public synchronized void write(byte b[], int off, int len) throws IOException { 
    if (len >= buf.length) { 
     /* If the request length exceeds the size of the output buffer, 
      flush the output buffer and then write the data directly. 
      In this way buffered streams will cascade harmlessly. */ 
     flushBuffer(); 
     out.write(b, off, len); 
     return; 
    } 
    if (len > buf.length - count) { 
     flushBuffer(); 
    } 
    System.arraycopy(b, off, buf, count, len); 
    count += len; 
} 
+0

कुछ मैं अभी तक नहीं मिला है - BufferedOutputStream के डिफ़ॉल्ट बफर आकार क्या है जावा 6 में? आप 8 केबी का जिक्र करते हैं - क्या जावा में डिफ़ॉल्ट है? 1.4.2 के लिए जावाडॉक्स का कहना है कि बफर 512 बाइट्स है, जिसका अर्थ है कि मैं जो कुछ लिखता हूं वह 200 से 400 बाइट प्रति सरणी के बीच गिरता है। हालांकि, यह जानकारी जावा 6 दस्तावेज से हटा दी गई है। –

+3

@ थॉमस - [स्रोत कोड को देख रहे हैं] (http://www.docjar.com/html/api/java/io/BufferedOutputStream.java.html#51), डिफ़ॉल्ट आकार 8192 है। मुझे लगता है कि वे एक नया "सबसे समझदार डिफ़ॉल्ट" प्रकट होने पर इसे बदलने में सक्षम होने के लिए डिफ़ॉल्ट आकार विनिर्देश को हटा दिया गया। यदि कोई विशिष्ट बफर आकार महत्वपूर्ण है, तो आप शायद इसे स्पष्ट रूप से निर्दिष्ट करना चाहते हैं। – gustafc

+1

@gustafc धन्यवाद। मैं हमेशा भूल जाता हूं कि मैं जावा स्रोत कोड देख सकता हूं। –

1

मैं हाल ही में आईओ प्रदर्शन का पता लगाने के प्रयास कर रहे हैं हो सकता है। मैंने जो देखा है, उससे सीधे FileOutputStream पर लिखने से बेहतर परिणाम सामने आए हैं; जिसे मैंने के लिए FileOutputStream के मूल कॉल के लिए जिम्मेदार ठहराया है। इसके अलावा, मैंने यह भी देखा है कि जब BufferedOutputStream की विलंबता सीधे FileOutputStream की ओर बढ़ने लगती है, तो यह बहुत अधिक उतार-चढ़ाव करता है यानी यह अचानक भी डबल-अप हो सकता है (मैं अभी तक क्यों नहीं ढूंढ पा रहा हूं)।

पीएस मैं जावा 8 का उपयोग कर रहा हूं और अभी इस पर टिप्पणी नहीं कर पाऊंगा कि मेरे अवलोकन पिछले जावा संस्करणों के लिए होंगे या नहीं।

यहाँ कोड मैं परीक्षण किया है, जहां मेरे इनपुट एक ~ 10KB फ़ाइल थी

public class WriteCombinationsOutputStreamComparison { 
    private static final Logger LOG = LogManager.getLogger(WriteCombinationsOutputStreamComparison.class); 

public static void main(String[] args) throws IOException { 

    final BufferedInputStream input = new BufferedInputStream(new FileInputStream("src/main/resources/inputStream1.txt"), 4*1024); 
    final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 
    int data = input.read(); 
    while (data != -1) { 
     byteArrayOutputStream.write(data); // everything comes in memory 
     data = input.read(); 
    } 
    final byte[] bytesRead = byteArrayOutputStream.toByteArray(); 
    input.close(); 

    /* 
    * 1. WRITE USING A STREAM DIRECTLY with entire byte array --> FileOutputStream directly uses a native call and writes 
    */ 
    try (OutputStream outputStream = new FileOutputStream("src/main/resources/outputStream1.txt")) { 
     final long begin = System.nanoTime(); 
     outputStream.write(bytesRead); 
     outputStream.flush(); 
     final long end = System.nanoTime(); 
     LOG.info("Total time taken for file write, writing entire array [nanos=" + (end - begin) + "], [bytesWritten=" + bytesRead.length + "]"); 
     if (LOG.isDebugEnabled()) { 
      LOG.debug("File reading result was: \n" + new String(bytesRead, Charset.forName("UTF-8"))); 
     } 
    } 

    /* 
    * 2. WRITE USING A BUFFERED STREAM, write entire array 
    */ 

    // changed the buffer size to different combinations --> write latency fluctuates a lot for same buffer size over multiple runs 
    try (BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("src/main/resources/outputStream1.txt"), 16*1024)) { 
     final long begin = System.nanoTime(); 
     outputStream.write(bytesRead); 
     outputStream.flush(); 
     final long end = System.nanoTime(); 
     LOG.info("Total time taken for buffered file write, writing entire array [nanos=" + (end - begin) + "], [bytesWritten=" + bytesRead.length + "]"); 
     if (LOG.isDebugEnabled()) { 
      LOG.debug("File reading result was: \n" + new String(bytesRead, Charset.forName("UTF-8"))); 
     } 
    } 
} 
} 

उत्पादन:

2017-01-30 23:38:59.064 [INFO] [main] [WriteCombinationsOutputStream] - Total time taken for file write, writing entire array [nanos=100990], [bytesWritten=11059] 

2017-01-30 23:38:59.086 [INFO] [main] [WriteCombinationsOutputStream] - Total time taken for buffered file write, writing entire array [nanos=142454], [bytesWritten=11059] 
+0

मैंने इसी तरह के परीक्षण चलाए और मैं पुष्टि कर सकता हूं कि 'BufferedOutputStream' का उपयोग करके लेखन फ़ाइलों को तेज़ लेकिन धीमा नहीं होता है, सबसे अधिक संभावना है क्योंकि डेटा लिखा जा रहा है पहले से ही ओएस के माध्यम से ओएस के माध्यम से कई स्तरों पर कैश किया गया है मध्यम। –

+0

@GOTO पुष्टि करने के लिए धन्यवाद। क्या ऐसे कोई संसाधन हैं जिनके बारे में आपको पता हो सकता है, जो मुझे आईओ और आंतरिक कैश के काम में गहरी खुदाई करने में मदद कर सकता है? –

+0

वास्तव में नहीं। अगर यह गुगलिंग में मदद करता है, तो फाइल कैशिंग घटकों को विंडोज़ में कैश मैनेजर और लिनक्स में पेज कैश कहा जाता है। हार्ड डिस्क और अन्य स्टोरेज डिवाइस भी आई/ओ कैश के विभिन्न प्रकार के साथ आते हैं (हालांकि मूल बातें शायद समान हैं)। –

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

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