2012-07-09 6 views
7

के लिए स्वचालित रूप से बफर आकार का चयन करना मेरे पास एक बहुत ही बुनियादी संदेह है। अक्सर, मुझे उन ऐप्स लिखना पड़ता है जो buffered फ़ाइल I/O का उपयोग करते हैं और हर बार मुझे बफर आकार चुनने की दुविधा का सामना करना पड़ता है और मैं अक्सर बहुत खराब परिणामों के साथ परीक्षण और त्रुटि कर रहा हूं। मैं जानना चाहता हूं कि कोई विधि या एल्गोरिदम है जो विंडोज़ में फ़ाइलों को संभालने के दौरान टेराकोपी जैसे अंतर्निहित प्लेटफॉर्म पर आधारित नौकरी के लिए इष्टतम बफर आकार निर्धारित कर सकता है। मैं मुख्य रूप से जीयूआई के लिए क्यूटी का उपयोग करता हूं।फ़ाइल I/O

यदि संभव हो तो सी/सी ++/सी #/जावा में एक छोटा सा उदाहरण बहुत सराहना की है!

धन्यवाद!

उत्तर

15

जावा में इष्टतम आमतौर पर एल 1 कैश आकार के आसपास होता है जो आम तौर पर 32 केबी होता है। जावा में, कम से कम 1024 बाइट्स या 1 एमबी चुनने से बहुत अंतर नहीं होता है (< 20%)

यदि आप क्रमशः डेटा पढ़ रहे हैं, तो आम तौर पर आपका ओएस यह पता लगाने के लिए पर्याप्त स्मार्ट है और आपके लिए डेटा प्रीफेच करता है।

आप क्या कर सकते हैं निम्नलिखित है। यह परीक्षण ब्लॉक आकार में एक महत्वपूर्ण अंतर दिखाने के लिए प्रतीत होता है।

public static void main(String... args) throws IOException { 
    for (int i = 512; i <= 2 * 1024 * 1024; i *= 2) 
     readWrite(i); 
} 

private static void readWrite(int blockSize) throws IOException { 
    ByteBuffer bb = ByteBuffer.allocateDirect(blockSize); 
    long start = System.nanoTime(); 
    FileChannel out = new FileOutputStream("deleteme.dat").getChannel(); 
    for (int i = 0; i < (1024 << 20); i += blockSize) { 
     bb.clear(); 
     while (bb.remaining() > 0) 
      if (out.write(bb) < 1) throw new AssertionError(); 
    } 
    out.close(); 
    long mid = System.nanoTime(); 
    FileChannel in = new FileInputStream("deleteme.dat").getChannel(); 
    for (int i = 0; i < (1024 << 20); i += blockSize) { 
     bb.clear(); 
     while (bb.remaining() > 0) 
      if (in.read(bb) < 1) throw new AssertionError(); 
    } 
    in.close(); 
    long end = System.nanoTime(); 
    System.out.printf("With %.1f KB block size write speed %.1f MB/s, read speed %.1f MB/s%n", 
      blockSize/1024.0, 1024 * 1e9/(mid - start), 1024 * 1e9/(end - mid)); 
} 

प्रिंट

With 0.5 KB block size write speed 96.6 MB/s, read speed 169.7 MB/s 
With 1.0 KB block size write speed 154.2 MB/s, read speed 312.2 MB/s 
With 2.0 KB block size write speed 201.5 MB/s, read speed 438.7 MB/s 
With 4.0 KB block size write speed 288.0 MB/s, read speed 733.9 MB/s 
With 8.0 KB block size write speed 318.4 MB/s, read speed 711.8 MB/s 
With 16.0 KB block size write speed 540.6 MB/s, read speed 1263.7 MB/s 
With 32.0 KB block size write speed 726.0 MB/s, read speed 1370.9 MB/s 
With 64.0 KB block size write speed 801.8 MB/s, read speed 1536.5 MB/s 
With 128.0 KB block size write speed 857.5 MB/s, read speed 1539.6 MB/s 
With 256.0 KB block size write speed 794.0 MB/s, read speed 1781.0 MB/s 
With 512.0 KB block size write speed 676.2 MB/s, read speed 1221.4 MB/s 
With 1024.0 KB block size write speed 886.3 MB/s, read speed 1501.5 MB/s 
With 2048.0 KB block size write speed 784.7 MB/s, read speed 1544.9 MB/s 

क्या इस परीक्षण प्रदर्शित नहीं करता है कि हार्ड ड्राइव केवल 60 एमबी का समर्थन करता है/s पढ़ता है और 40 MB/s लिखता है। आप परीक्षण कर रहे हैं कैश के अंदर और बाहर गति। यदि यह आपकी एकमात्र प्राथमिकता थी, तो आप मेमोरी मैप की गई फ़ाइल का उपयोग करेंगे।

int blockSize = 32 * 1024; 
ByteBuffer bb = ByteBuffer.allocateDirect(blockSize); 
FileChannel out = new FileOutputStream("deleteme.dat").getChannel(); 
for (int i = 0; i < (1024 << 20); i += blockSize) { 
    bb.clear(); 
    while (bb.remaining() > 0) 
     if (out.write(bb) < 1) throw new AssertionError(); 
} 
out.close(); 

long start = System.nanoTime(); 
FileChannel in = new FileInputStream("deleteme.dat").getChannel(); 
MappedByteBuffer map = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size()); 
in.close(); 
long end = System.nanoTime(); 
System.out.printf("Mapped file at a rate of %.1f MB/s%n", 
     1024 * 1e9/(end - start)); 

प्रिंट

Mapped file at a rate of 589885.5 MB/s 

यह इतनी तेजी से, क्योंकि यह सिर्फ सीधे आवेदन की स्मृति (ताकि कोई नकल की आवश्यकता है)

+0

शुद्ध उत्कृष्टता !!! यह जावा में लगभग ईश्वर है ... लेकिन मुझे नहीं पता कि मैं इसे सी/सी ++ पर कितनी दूर कार्यान्वित कर सकता हूं क्योंकि मेरे अधिकांश ऐप्स मूल हैं और जितनी जल्दी हो सके उतनी जल्दी होने की आवश्यकता है। एक और बात: क्या आपकी विधि उन ऐप्स के लिए अच्छी है जो इसे वापस लिखने से पहले डेटा पर काम करती हैं (एन्क्रिप्शन ऐप्स) ?? बीटीडब्ल्यू, Math.pow ("धन्यवाद !!!!", (10/0)); –

+0

एन्क्रिप्शन ऐप्स, जैसे अधिकांश ऐप्स जो प्रक्रिया करते हैं, डेटा सीपीयू बाध्य होने की संभावना है। इस मामले में, बफर आकार की कोई फर्क नहीं पड़ता क्योंकि सीपीयू लागत बहुत अधिक है। आपके कैश के आकार में अधिक अंतर हो सकता है। IMHO जावा में आप जो भी कर सकते हैं आप सी या सी ++ में कर सकते हैं। –

+1

अच्छी व्याख्या देखें, मैं +1 करता हूं – aswzen

1

मेरे पास में ओएस डिस्क कैश में डेटा नक्शे है सी में इस कोड को देखें:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 
#include <stdio.h> 

int main() 
{ 
    struct stat fi; 
    stat("/", &fi); 
    printf("%d\n", fi.st_blksize); 
    return 0; 
} 

यह इष्टतम ब्लॉक आकार देता है। ऐसा करने के लिए आपको इसका इस्तेमाल करने की ज़रूरत है। मैं इष्टतम प्रदर्शन के लिए 16 * ब्लॉक आकार के साथ गंतव्य के लिए स्ट्रीम स्रोत का उपयोग करता हूं। चूंकि यह परीक्षण कुछ हार्डवेयर/ओएस के साथ निष्क्रिय होने पर एक पीसी के साथ सर्वश्रेष्ठ प्रकट करेगा। लेकिन वास्तविक मामला नहीं।

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