4

NetCDF ファイルを読み込んでおり、各配列を float 配列として読み込んでから、float 配列を新しいファイルに書き込みたいと考えています。float 配列を読み込んでから (DataOutputStream を使用して) 配列内の各要素を反復処理すれば動作させることができますが、これは非常に遅く、私の NetCDF ファイルは 1GB を超えています。

ObjectOutputStream を使用してみましたが、これは余分なバイト数の情報を書き込みます。

では、要約します。1. NetCDF ファイルを開く 2. NetCDF ファイルから float 配列 x を読み取る 3. float 配列 x を 1 ステップで生データ ファイルに書き込む 4. x+1 でステップ 2 を繰り返す

4

5 に答える 5

3

わかりました。読み取りには1GB、書き込みには1GBがあります。ハードドライブによっては、読み取り速度が約100 MB / s、書き込み速度が60 MB/sになる場合があります。これは、読み取りと書き込みに約27秒かかることを意味します。

あなたのドライブの速度はどれくらいですか、そしてこれよりどれくらい遅いですか?

処理せずにディスクの速度をテストする場合は、最近アクセスしていない(つまり、ディスクキャッシュにない)ファイルをコピーするのにかかる時間を測定します。これにより、最小遅延がわかります。ファイルからほとんどのデータを読み取ってから書き込むことを期待できます(つまり、処理やJavaを使用せずに)


ループの少ないデータのコピーを実行する方法を知りたい人のために、つまり、ループするメソッドを呼び出すだけではありません。

FloatBuffer src = // readable memory mapped file.
FloatByffer dest = // writeable memory mapped file.
src.position(start);
src.limit(end);
dest.put(src);

混合タイプのデータがある場合は、概念的に一度に1バイトをコピーするByteBufferを使用できますが、実際には、一度に8バイト以上をコピーするために長いタイプまたはより広いタイプを使用できます。つまり、CPUが実行できることは何でも。

小さなブロックの場合、これはループを使用しますが、大きなブロックの場合、OSでページマッピングのトリックを使用できます。いずれにせよ、それがどのように行われるかはJavaで定義されていませんが、データをコピーするための最速の方法である可能性があります。

これらのトリックのほとんどは、すでにメモリ内にあるファイルをキャッシュされたファイルにコピーしている場合にのみ違いがあります。ディスクからファイルを読み取るか、ファイルが大きすぎて物理ディスクのIO帯域幅をキャッシュできないとすぐに、本当に重要なのは物理ディスクのIO帯域幅だけです。

これは、CPUがメインメモリに6 GB / sでデータをコピーできるが、ハードドライブには60〜100 MB/sしかコピーできないためです。CPU /メモリ内のコピーが2倍、10倍、または50倍遅い場合でも、ディスクを待機しています。注:バッファリングがない場合、これは完全に可能であり、さらに悪いことになりますが、単純なバッファリングがあれば、CPUはディスクよりも高速になります。

于 2011-09-13T17:30:44.967 に答える
1

私は同じ問題に遭遇したので、将来の参考のためにここに私の解決策をダンプします。

float の配列を繰り返し処理し、それぞれに対して DataOutputStream.writeFloat を呼び出すのは非常に時間がかかります。代わりに、フロートを自分でバイト配列に変換し、その配列を一度に書き込みます。

遅い:

DataOutputStream out = ...;
for (int i=0; i<floatarray.length; ++i)
    out.writeFloat(floatarray[i]);

はるかに高速

DataOutputStream out = ...;
byte buf[] = new byte[4*floatarray.length];
for (int i=0; i<floatarray.length; ++i)
{
    int val = Float.floatToRawIntBits(probs[i]);
    buf[4 * i] = (byte) (val >> 24);
    buf[4 * i + 1] = (byte) (val >> 16) ;
    buf[4 * i + 2] = (byte) (val >> 8);
    buf[4 * i + 3] = (byte) (val);
}

out.write(buf);

配列が非常に大きい (>100k) 場合は、バッファ配列でのヒープ オーバーフローを避けるためにチャンクに分割します。

于 2012-10-29T08:45:00.477 に答える
1

1) 書き込み時に BufferedOutputStream を使用すると、100 倍の高速化が得られます。

2) 読み取るときは、読み取りごとに少なくとも 10K を読み取ります。おそらく 100K の方が優れています。

3) コードを投稿します。

于 2011-12-01T23:47:35.587 に答える
0

横方向の解決策:

これが1回限りの世代であり(またはAntスクリプトで自動化する場合)、ある種のUnix環境にアクセスできる場合は、Javaで行う代わりにNCDUMPを使用できます。何かのようなもの:

ncdump -v your_variable your_file.nc | [awk] > float_array.txt

必要に応じて、-pオプションを使用してフロートの精度を制御できます。3GBのNetCDFファイルで実行したところ、正常に機能しました。私はJavaが大好きですが、これはおそらくあなたがやりたいことをするための最も速い方法です。

于 2011-10-23T02:43:58.477 に答える
0

Unidata NetCDFライブラリを使用している場合、問題は書き込みではなく、NetCDFライブラリのキャッシュメカニズムにある可能性があります。

     NetcdfFile file = NetcdfFile.open(filename);
     Variable variable = openFile.findVariable(variable name);
     for (...) {
          read data
          variable.invalidateCache();
      }
于 2011-10-21T17:51:45.737 に答える