2

Java 5.0 x64 (Windows XP 上) を使用して、大きなファイル (~4GB) のワンススルー読み取りを実行しようとしています。

最初はファイルの読み取り速度は非常に高速ですが、徐々にスループットが大幅に低下し、時間の経過とともにマシンが非常に応答しなくなったように見えます。

私は ProcessExplorer を使用してファイル I/O 統計を監視しました。プロセスは最初は 500MB/秒を読み取っているように見えますが、この速度は徐々に約 20MB/秒に低下します。

特にJavaを使用して大きなファイルを読み取る場合に、ファイルI / Oレートを維持するための最良の方法に関するアイデアはありますか?

「間隔時間」が増加し続けていることを示すテストコードを次に示します。少なくとも 500MB のファイルを Main に渡すだけです。

import java.io.File;
import java.io.RandomAccessFile;

public class MultiFileReader {

public static void main(String[] args) throws Exception {
    MultiFileReader mfr = new MultiFileReader();
    mfr.go(new File(args[0]));
}

public void go(final File file) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    long fileLength = raf.length();
    System.out.println("fileLen: " + fileLength);
    raf.close();

    long startTime = System.currentTimeMillis();
    doChunk(0, file, 0, fileLength);
    System.out.println((System.currentTimeMillis() - startTime) + " ms");
}

public void doChunk(int threadNum, File file, long start, long end) throws Exception {
    System.out.println("Starting partition " + start + " to " + end);
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    raf.seek(start);

    long cur = start;
    byte buf[] = new byte[1000];
    int lastPercentPrinted = 0;
    long intervalStartTime = System.currentTimeMillis();
    while (true) {
        int numRead = raf.read(buf);
        if (numRead == -1) {
            break;
        }
        cur += numRead;
        if (cur >= end) {
            break;
        }

        int percentDone = (int)(100.0 * (cur - start) / (end - start));
        if (percentDone % 5 == 0) {
            if (lastPercentPrinted != percentDone) {
                lastPercentPrinted = percentDone;
                System.out.println("Thread" + threadNum + " Percent done: " + percentDone + " Interval time: " + (System.currentTimeMillis() - intervalStartTime));
                intervalStartTime = System.currentTimeMillis();
            }
        }
    }
    raf.close();
}
}

ありがとう!

4

5 に答える 5

10

ディスクから本当に毎秒 500MB を取得しているとは思えません。データはオペレーティング システムによってキャッシュされている可能性があります。実際にディスクにアクセスすると、1 秒あたり 20MB になります。

これは、Vista Resource Manager のディスク セクションに表示される可能性が非常に高く、ローテクな方法は、ディスク ドライブをリッスンすることです :)

于 2008-12-04T21:37:27.110 に答える
1

ここでは Java ガベージ コレクタがボトルネックになる可能性があります。

doChunk() への各呼び出しによって割り当てられるのではなく、再利用されるように、バッファーを大きくしてクラス専用にします。

public class MultiFileReader {

   private byte buf[] = new byte[256*1024];

   ...

}
于 2008-12-05T15:23:10.047 に答える
1

特定のハードウェアやその他の状況によっては、20MB/秒をはるかに超える処理を行うにはかなりの労力が必要になる場合があります。

おそらく、500MB/秒がどれほど完全にスケール外であるかを本当に理解していないと思います...

あなたは何を望んでいますか、そしてあなたの特定のドライブが理論的にそれが可能であることを確認しましたか?

于 2008-12-04T21:58:55.880 に答える
0

static void read3() throws IOException {

        // read from the file with buffering
        // and with direct access to the buffer

        MyTimer mt = new MyTimer();
        FileInputStream fis = 
                     new FileInputStream(TESTFILE);
        cnt3 = 0;
        final int BUFSIZE = 1024;
        byte buf[] = new byte[BUFSIZE];
        int len;
        while ((len = fis.read(buf)) != -1) {
            for (int i = 0; i < len; i++) {
                if (buf[i] == 'A') {
                    cnt3++;
                }
            }
        }
        fis.close();
        System.out.println("read3 time = " 
                                + mt.getElapsed());
    }

http://java.sun.com/developer/JDCTechTips/2002/tt0305.htmlから

最適なバッファー サイズは、オペレーティング システムによって異なる場合があります。あなたのものは多分to0小さいです。

于 2008-12-05T14:55:39.477 に答える
0

JConsole を使用して、メモリ使用量などのアプリを監視できます。500 MB/秒というのは、本当のように思えます。

使用される実装と VM 引数に関する詳細情報が役立ちます。

于 2008-12-04T21:43:06.600 に答える