8

私はかなり基本的な疑問を持っています。多くの場合、バッファファイルI / Oを使用するアプリを作成する必要があり、バッファサイズを選択するというジレンマに直面するたびに、試行錯誤を繰り返してかなり厄介な結果になります。Windowsでファイルを処理するときにTeracopyが行うように、基盤となるプラットフォームに基づいてジョブに最適なバッファサイズを自動的に決定できる方法またはアルゴリズムがあるかどうかを知りたいです。私は主にGUIにQtを使用しています。

可能であれば、C / C ++ / C#/Javaの小さな例をいただければ幸いです。

ありがとう!

4

2 に答える 2

15

Javaでは、最適なのは通常、L1キャッシュサイズ(通常は32 KB)です。Javaでは、少なくとも1024バイトまたは1 M​​Bを選択しても、大きな違いはありません(<20%)

データを順番に読み取っている場合、通常、OSはこれを検出し、データをプリフェッチするのに十分な機能を備えています。

できることは次のとおりです。このテストは、使用されるブロックサイズに大きな違いがあることを示しているようです。

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 MB/sの読み取りと40MB/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

これは、OSディスクキャッシュ内のデータをアプリケーションのメモリに直接マップするだけなので、非常に高速です(したがって、コピーは必要ありません)。

于 2012-07-09T12:05:37.300 に答える
1

私はCでこのコードを見ました:

#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*ブロックサイズのストリームソースからデスティネーションを使用します。このテストでは、ハードウェア/OSを使用してアイドル状態のPCで最適な結果が得られるためです。しかし、実際のケースではありません。

于 2012-07-18T23:04:53.843 に答える