計算負荷の高いタスクを実行しながらデータをディスクに保存する効率的な方法

StackOverflow https://stackoverflow.com/questions/1014113

質問

非常にCPUを集中的に使用する(procバウンド)科学ソフトウェアに取り組んでいますが、かなり頻繁にディスクにデータを書き込む必要があります(i / oバウンド)。

この(OpenMP)に並列化を追加しているので、ディスクへの書き込みのニーズに対処する最善の方法は何かと思っています。 シミュレーションがHDDで待機する必要はありません(これは現在実行中です)。

このための「ベストプラクティス」を探しています。速度が最も重要なことです(これらは非常に長いシミュレーションになる可能性があります)。

ありがとう 〜アレックス

最初の考え:

別のプロセスを持つことで、ディスクへの実際の書き込みが行われるため、シミュレーションには2つのプロセスがあります。1つはCPUバインド(シミュレーション)で、もう1つはIOバインド(ファイルの書き込み)です。これは複雑に聞こえます。

おそらくパイプ/バッファですか?私はこれらに新しいので、多分それは可能な解決策かもしれません。

役に立ちましたか?

解決

OpenMPをプログラムに実装する場合、並列セクションの #pragma omp single または #pragma omp master を使用してファイルに保存することをお勧めします。これらのプラグマでは、1つのスレッドのみが何かを実行できます。したがって、コードは次のようになります。

#pragma omp parallel
{
    // Calculating the first part
    Calculate();

    // Using barrier to wait all threads
    #pragma omp barrier

    #pragma omp master
    SaveFirstPartOfResults();

    // Calculate the second part
    Calculate2();

    #pragma omp barrier

    #pragma omp master
    SaveSecondPart();

    Calculate3();

    // ... and so on
}

ここではスレッドのチームが計算を行いますが、単一のスレッドのみが結果をディスクに保存します。

ソフトウェアパイプラインのように見えます。 Intel Threading Building Blocksライブラリのtbb :: pipelineパターンを検討することをお勧めします。 http://cache-www.intel.com/cd/00/00/30/11/301132_301132.pdf#page=25 。 4.2項をお読みください。彼らは問題を解決しました:1つのスレッドはドライブから読み取り、2つ目は読み取り文字列を処理し、3つ目はドライブに保存します。

他のヒント

最善の方法は、完全に新しいプロセスではなく、データを保存するために別のスレッドを作成することです。新しいプロセスでは、プロセスの境界を越えて保存するデータを通信する必要があるという問題が発生します。これにより、新しい問題が発生します。

頭に浮かぶ最初の解決策は、あなたが言ったこととほぼ同じです-シムからライターへの一方向のパイプを使用して、独自のプロセスでディスク書き込みを行います。ライターは、可能な限り高速で書き込みを行います(パイプから新しいデータを引き出します)。これに関する問題は、シムがライターよりも先に進みすぎると、シムがパイプの書き込みをブロックすることになり、削除時にI / Oがバインドされることです。

問題は、実際にはシミュレーションサイクルが結果を吐き出すまで完了しないことです。

2番目に起こることは、非ブロッキングI / Oを使用することです。シムが書き込む必要があるときはいつでも、ノンブロッキングI / Oを介して行う必要があります。次に書き込む必要がある場合、新しいI / O操作を開始する前に、以前のI / O操作の結果を取得することができます(おそらくわずかな待機が発生します)。これにより、シミュレーションを書き込みよりもはるかに先に進めることなく、I / Oと並行して可能な限りシミュレーションを実行し続けます。

最初の解決策は、シミュレーションの処理サイクルが変動する場合(書き込みの時間よりも短い場合があり、長い場合もあります)の方が良いでしょう。

処理サイクルが常に(またはほぼ常に)書き込み時間より短くなる場合  パイプを使用せずにノンブロッキングI / Oを使用することもできます。パイプを使用すると最終的に満杯になり、シムがI / Oでハングアップするためです。

あなたはCPUとIOに縛られているので、推測させてください:まだ十分なメモリがありますよね?

その場合、メモリ内のディスクに書き込む必要があるデータを一定の範囲でバッファリングする必要があります。通常、大量のデータを書き込む方が、小さい部分を書き込むよりもはるかに高速です。

書き込み自体:メモリマップIOの使用を検討してください。ベンチマークを行ってからしばらく経ちましたが、前回行ったときはかなり速くなりました。

また、CPUとIOを少しだけトレードすることもできます。現在、何らかの生の非圧縮データとしてデータを書き込んでいると思いますか?単純な圧縮スキームを使用して書き込まれるデータの量を減らすと、IOパフォーマンスが得られる場合があります。 ZLIBライブラリは操作が非常に簡単で、最低の圧縮レベルで非常に高速に圧縮します。データの性質に依存しますが、冗長性が非常に大きい場合は、非常に粗雑な圧縮アルゴリズムでもIOバウンドの問題を解消できます。

1つのスレッドは、計算負荷の高いプロセスのステップを継続的に実行し、部分結果を部分結果のキューに追加します。別のスレッドは、部分的な結果をキューから継続的に削除し、ディスクに書き込みます。キューへのアクセスを同期してください。キューはリストのようなデータ構造で、アイテムを最後に追加したり、アイテムを前面から削除したりできます。

アプリケーションにCPU用とハードディスク用の2つのスレッドを作成します。

CPUスレッドが、完了したデータをキューにプッシュし、データが入ってくるとハードディスクスレッドがそこからプルします。

この方法では、CPUがデータを削除し、他の誰かがそれを処理できるようにし、ハードドライブはキュー内のデータを辛抱強く待機します。

実装に関しては、キューを共有メモリタイプのオブジェクトとして実行できますが、パイプはまさにあなたが探しているものだと思います。 CPUは必要に応じて単純にパイプに書き込みます。ハードディスク側では、パイプを読むだけで、有効なデータが得られたらそこから先に進みます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top