मैंने एक छोटी आईओ कक्षा लागू की है, जो विभिन्न डिस्क पर एकाधिक और एक ही फाइलों से पढ़ सकता है (उदाहरण के लिए एक ही फाइल वाली दो हार्ड डिस्क)। अनुक्रमिक मामले में, दोनों डिस्क फ़ाइल पर औसत में 60 एमबी/एस पढ़ते हैं, लेकिन जब मैं एक इंटरलीव किया जाता हूं (उदा। 4k डिस्क 1, 4k डिस्क 2 फिर गठबंधन), प्रभावी पढ़ने की गति बढ़ने के बजाय 40 एमबी/एस तक कम हो जाती है?इंटरलीव किए गए समांतर फ़ाइल अनुक्रमिक पढ़ने से धीमी गति से पढ़ी जाती है?
संदर्भ: विन 7 + जेडीके 7 बी 70, 2 जीबी रैम, 2.2 जीबी परीक्षण फ़ाइल। असल में, मैं Win7 के ReadyBoost और RAID x को एक गरीब व्यक्ति के फैशन में नकल करने का प्रयास करता हूं।
दिल में, जब कक्षा में एक पढ़ा() जारी किया जाता है, तो यह एक निश्चित स्थिति और लंबाई से पूर्व-खोले गए RandomAccessFile को पढ़ने के निर्देशों के साथ दो रननेबल बनाता है। निष्पादक सेवा और Future.get() कॉल का उपयोग करते समय, दोनों समाप्त होने पर, डेटा पढ़ने को एक आम बफर में कॉपी किया जाता है और कॉलर पर वापस आ जाता है।
क्या मेरे दृष्टिकोण में कोई अवधारणात्मक त्रुटि है? (उदाहरण के लिए, ओएस कैशिंग तंत्र हमेशा प्रतिक्रिया करेगा?)
protected <T> List<T> waitForAll(List<Future<T>> futures)
throws MultiIOException {
MultiIOException mex = null;
int i = 0;
List<T> result = new ArrayList<T>(futures.size());
for (Future<T> f : futures) {
try {
result.add(f.get());
} catch (InterruptedException ex) {
if (mex == null) {
mex = new MultiIOException();
}
mex.exceptions.add(new ExceptionPair(metrics[i].file, ex));
} catch (ExecutionException ex) {
if (mex == null) {
mex = new MultiIOException();
}
mex.exceptions.add(new ExceptionPair(metrics[i].file, ex));
}
i++;
}
if (mex != null) {
throw mex;
}
return result;
}
public int read(long position, byte[] output, int start, int length)
throws IOException {
if (start < 0 || start + length > output.length) {
throw new IndexOutOfBoundsException(
String.format("start=%d, length=%d, output=%d",
start, length, output.length));
}
// compute the fragment sizes and positions
int result = 0;
final long[] positions = new long[metrics.length];
final int[] lengths = new int[metrics.length];
double speedSum = 0.0;
double maxValue = 0.0;
int maxIndex = 0;
for (int i = 0; i < metrics.length; i++) {
speedSum += metrics[i].readSpeed;
if (metrics[i].readSpeed > maxValue) {
maxValue = metrics[i].readSpeed;
maxIndex = i;
}
}
// adjust read lengths
int lengthSum = length;
for (int i = 0; i < metrics.length; i++) {
int len = (int)Math.ceil(length * metrics[i].readSpeed/speedSum);
lengths[i] = (len > lengthSum) ? lengthSum : len;
lengthSum -= lengths[i];
}
if (lengthSum > 0) {
lengths[maxIndex] += lengthSum;
}
// adjust read positions
long positionDelta = position;
for (int i = 0; i < metrics.length; i++) {
positions[i] = positionDelta;
positionDelta += (long)lengths[i];
}
List<Future<byte[]>> futures = new LinkedList<Future<byte[]>>();
// read in parallel
for (int i = 0; i < metrics.length; i++) {
final int j = i;
futures.add(exec.submit(new Callable<byte[]>() {
@Override
public byte[] call() throws Exception {
byte[] buffer = new byte[lengths[j]];
long t = System.nanoTime();
long t0 = t;
long currPos = metrics[j].handle.getFilePointer();
metrics[j].handle.seek(positions[j]);
t = System.nanoTime() - t;
metrics[j].seekTime = t * 1024.0 * 1024.0/
Math.abs(currPos - positions[j])/1E9 ;
int c = metrics[j].handle.read(buffer);
t0 = System.nanoTime() - t0;
// adjust the read speed if we read something
if (c > 0) {
metrics[j].readSpeed = (alpha * c * 1E9/t0/1024/1024
+ (1 - alpha) * metrics[j].readSpeed) ;
}
if (c < 0) {
return null;
} else
if (c == 0) {
return EMPTY_BYTE_ARRAY;
} else
if (c < buffer.length) {
return Arrays.copyOf(buffer, c);
}
return buffer;
}
}));
}
List<byte[]> data = waitForAll(futures);
boolean eof = true;
for (byte[] b : data) {
if (b != null && b.length > 0) {
System.arraycopy(b, 0, output, start + result, b.length);
result += b.length;
eof = false;
} else {
break; // the rest probably reached EOF
}
}
// if there was no data at all, we reached the end of file
if (eof) {
return -1;
}
sequentialPosition = position + (long)result;
// evaluate the fastest file to read
double maxSpeed = 0;
maxIndex = 0;
for (int i = 0; i < metrics.length; i++) {
if (metrics[i].readSpeed > maxSpeed) {
maxSpeed = metrics[i].readSpeed;
maxIndex = i;
}
}
fastest = metrics[maxIndex];
return result;
}
(मैट्रिक्स सरणी में FileMetrics पढ़ने की गति की माप शामिल adaptively विभिन्न इनपुट चैनलों की बफ़र आकार निर्धारित करने के लिए - अल्फा = 0 और readSpeed साथ अपने परीक्षण में = 1 परिणाम समान वितरण)
संपादित मैं एक गैर उलझ परीक्षण भाग गया (जैसे अलग धागे में स्वतंत्र रूप से दो फ़ाइलों को पढ़ने के।) और मैं 110MB/एस की एक संयुक्त प्रभावी गति मिल गया है।
संपादित 2 मुझे लगता है कि मुझे पता है कि यह क्यों हो रहा है।
जब मैं समांतर और अनुक्रम में पढ़ता हूं, तो यह डिस्क के अनुक्रमिक पठन नहीं है, बल्कि इंटरलविंग (और संभावित रूप से आवंटन तालिका लुकअप के साथ छेड़छाड़) के कारण पढ़ने-छोड़ने-पढ़ने-छोड़ने के पैटर्न को नहीं पढ़ता है। यह मूल रूप से प्रति डिस्क प्रभावी पढ़ने की गति को आधे या बदतर तक कम कर देता है।
यह एक दिलचस्प समस्या है और समाधान खोजने के लिए आपके लिए अच्छा है। मुझे लगता है कि आपको समाधान को उत्तर के रूप में लिखना चाहिए और अपना जवाब स्वीकार करना चाहिए। – Guss