3

データをクラスタリングするために作成した反復アルゴリズム中に (多かれ少なかれ) ランダムにアクセスする double の大きな (3Gb) バイナリ ファイルがあります。各反復では、ファイルから約 50 万回の読み取りと、新しい値の約 10 万回の書き込みが行われます。

このように FileChannel を作成します...

f = new File(_filename);
_ioFile = new RandomAccessFile(f, "rw");
_ioFile.setLength(_extent * BLOCK_SIZE);
_ioChannel = _ioFile.getChannel();

次に、double のサイズのプライベート ByteBuffer を使用して、そこから読み取ります

private ByteBuffer _double_bb = ByteBuffer.allocate(8);

私の読み取りコードは次のようになります

public double GetValue(long lRow, long lCol) 
{
    long idx = TriangularMatrix.CalcIndex(lRow, lCol);
    long position = idx * BLOCK_SIZE;
    double d = 0;
    try 
    {
        _double_bb.position(0);
        _ioChannel.read(_double_bb, position);
        d = _double_bb.getDouble(0);
    } 

    ...snip...

    return d;
}

そして私はそれにこのように書いています...

public void SetValue(long lRow, long lCol, double d) 
{
    long idx = TriangularMatrix.CalcIndex(lRow, lCol);
    long offset = idx * BLOCK_SIZE;
    try 
    {
        _double_bb.putDouble(0, d);
        _double_bb.position(0);
        _ioChannel.write(_double_bb, offset);
    } 

    ...snip...

}

コードの繰り返しにかかる時間は、読み取り回数にほぼ比例して増加します。読み取り回数を最小限に抑えるために、周囲のコードに多くの最適化を追加しましたが、現時点では回避したいアルゴリズムの動作を根本的に変更することなく、必要と思われるコア セットにいます。

私の質問は、読み取り/書き込みコードまたは JVM 構成に、読み取りを高速化するためにできることがあるかどうかです。ハードウェアを変更できることはわかっていますが、その前に、問題からソフトウェア ジュースを最後の一滴まで絞り出したことを確認したいと考えています。

前もって感謝します

4

5 に答える 5

4

に読み込む代わりに、ByteBufferファイル マッピングを使用しますFileChannel.map()

また、ストレージへのアクセスGetValue(row, col)方法についてもあまり説明していません。多かれ少なかれランダムですかSetValue(row, col)?私が念頭に置いているアイデアは次のとおりです。画像処理のために、、、、のようなピクセルにアクセスして平均値を取得する必要がある場合があります。コツは、データを 8 x 8 または 16 x 16 ブロックに編成することです。そうすることで、関心のあるさまざまなピクセルを連続したメモリ領域 (できればキャッシュ内) に保持することができます。rowcolrow + 1row - 1col - 1col + 1

このアイデアをアルゴリズムに置き換えることができます (該当する場合)。ファイルの一部を一度マップすると、マップされたばかりのこの部分に対するさまざまな呼び出しGetValue(row, col)SetValue(row, col)作業が行われます。

于 2009-12-22T09:00:47.463 に答える
4

ファイルが通常のハードディスクに保存されている限り、アクセスの局所性を与える方法でデータを整理することにより、可能な限り最大のスピードアップを得ることができます。ファイルの領域。

HD 上のランダムなスポットへのアクセスは、最新の PC で最も遅く、他の何よりも約 10,000 倍の時間がかかるため、これは何よりも重要です。

そのため、一度にデータセットの一部 (メモリ内の HD キャッシュに問題なく収まるほど小さい) だけを処理して、結果を結合できる場合は、それを実行します。

または、ファイルを SSD または (より良い) RAM に保存して、問題を回避します。シンプルなサムドライブに保存するだけでも、大きな改善になる可能性があります.

于 2009-12-22T09:48:25.090 に答える
1

おそらく、読み取りの数を減らすことができれば、物事はより速く進みます。

3Gbは64ビットJVMとしては巨大ではないため、かなりの量のファイルがメモリに収まります。

ファイルをキャッシュする「ページ」として扱うとします。値を読み取るときは、その周囲のページを読み取り、メモリに保持します。次に、さらに読み取りを行う場合は、最初にキャッシュを確認してください。

または、容量がある場合は、処理の開始時にすべてをメモリに読み込みます。

于 2009-12-22T08:53:38.797 に答える
1
  1. バイト単位でアクセスすると、常にパフォーマンスが低下します (Java に限らず)。より大きなブロック (行や列など) の読み取り/書き込みを試みます。

  2. そのような量のデータを処理するために、データベース エンジンに切り替えてみませんか? すべての最適化を処理します。

この記事はあなたを助けるかもしれません...

于 2009-12-22T09:03:06.210 に答える
1

raw ファイル アクセス ルーチンを使用するのではなく、大量のデータとランダム読み取りを管理するために設計されたライブラリの使用を検討することをお勧めします。

HDFファイル形式が適している場合があります。Java APIがありますが、純粋な Java ではありません。Apache Style ライセンスの下でライセンスされています。

于 2009-12-22T09:20:39.990 に答える