0

プログラムの順次バージョンが既に存在し、単一の入力ファイルと他の単一の出力ファイルに対して一連の「読み取り-計算-書き込み」操作を実装していると考えてください。「読み取り」および「書き込み」操作は、変更が困難な (しかし可能である) サードパーティのライブラリ関数によって実行されますが、「計算」関数はプログラム自体によって実行されます。読み書きライブラリ関数は、内部フラグと内部メモリ バッファで動作するため、スレッド セーフではないようです。

プログラムが CPU バウンドであることが判明し、プログラムのマルチプロセッサ バージョンを設計しOpenMPてその目的で使用することにより、複数の CPU (最大 80) を利用してプログラムを改善する予定です。アイデアは、同じ単一の入力と単一の出力を持つ複数の「計算」関数をインスタンス化することです。

読み取り、データ転送、計算、およびデータ ストレージへの一貫したアクセスを保証するために何かを行う必要があることは明らかです。考えられる解決策は次のとおりです。(ハード) IO ライブラリ関数をスレッドセーフな方法で書き直す、(中程度) データ キャッシャーとしても機能する IO 関数のスレッドセーフなラッパーを作成する。

OpenMPスレッドセーフの仮定に準拠するためにシングルスレッドコードを変換、ラップ、または書き直すという主題をカバーする一般的なパターンはありますか?

EDIT1: プログラムは、変更を加えてマルチスレッド化するのに十分なほど新鮮です (または、通常、マルチスレッド化、マルチプロセッシング、またはその他の方法で実装された並列プログラム)。

4

2 に答える 2

1

簡単な応答として、単一のファイルを処理して別のファイルに書き込む場合、openMP を使用すると、IO 部分にあまり注意を払うことなく、プログラムのシーケンシャル バージョンをマルチスレッド バージョンに簡単に変換できます。それ自体は並列化できます。

これは、通常、メイン スレッドが IO を処理するためです。データのチャンクが大きすぎて一度に読み取ることができず、計算アルゴリズムが小さなチャンクを処理できないためにこれを達成できない場合は、openMP API を使用して各スレッドの IO を同期できます。これは、新しいデータの読み取りまたは書き込みができるように、アプリケーション全体が停止または他のスレッドの計算が終了するまで待機するという意味ではなく、読み取りおよび書き込み部分のみをアトミックに実行する必要があることを意味します。

たとえば、順次申請の流れが次のようになっているとします。

1) Read
2) compute
3) Write

本当に並列化でき、データの各チャンクを各スレッド内から読み取る必要がある場合、各スレッドは次の設計に従うことができます。

1) Synchronized read of chunk from input (only one thread at the time could execute this section)
2) Compute chunk of data (done in parallel)
3) Synchronized write of computed chunk to output (only one thread at the time could execute this section)

チャンクを読み取ったのと同じ順序で書き込む必要がある場合は、最初にバッファリングするか、正しい位置に fseek などの別の戦略を採用する必要がありますが、それは出力ファイルのサイズが最初からわかっているかどうかによって異なります。 ..

デフォルトは計算アルゴリズムに最適ではない可能性があるため、openMP スケジューリング戦略には特に注意してください。また、読み取った入力ファイルのオフセットなど、スレッド間で結果を共有する必要がある場合は、openMP API が提供するリダクション操作を使用できます。これは、コードの一部をすべてのスレッド間でアトミックに実行するよりもはるかに効率的です。 、グローバル変数を更新するためだけに、openMP は書き込みが安全な時期を認識しています。

編集:

「読み取り、処理、書き込み」操作に関しては、すべてのワーカー間で読み取りと書き込みをアトミックに保つ限り、問題が発生する理由は考えられません。読み取られたデータが内部バッファーに格納されていて、すべてのワーカーがアトミックにアクセスしている場合でも、そのデータはまったく同じ順序で取得されます。そのチャンクを出力ファイルに保存するときにのみ特別な注意を払う必要があります。これは、各ワーカーが属性付きチャンクの処理を終了する順序がわからないためです。まだ処理中です。各ワーカーが各チャンクの位置を追跡する必要があるだけで、最後に出力ファイルに保存されてから一連の完成したチャンクが得られるまで、保存する必要があるチャンクへのポインターのリストを保持できます。

内部バッファ自体が心配な場合 (そして、あなたが話しているライブラリがわからないので、間違っている可能性があることに注意してください)、データの一部のチャンクに対してリクエストを行う場合、その内部バッファのみを変更する必要があります。あなたがそのデータを要求した後、データがあなたに返される前; そして、その要求をアトミックに行ったので (つまり、他のすべてのワーカーは順番に並んでいる必要があります)、次のワーカーが自分のデータを要求したときに、その内部バッファーは、最後のワーカーがそのデータを受け取ったときと同じ状態になっている必要があります。かたまり。ライブラリが特に、チャンク自体のコピーではなく、内部バッファーの位置へのポインターを返すと述べている場合でも、アトミック読み取り操作全体のロックを解放する前に、ワーカーのメモリにコピーを作成できます。

私が提案したパターンが正しく守られていれば、アルゴリズムの同じ逐次バージョンでは見つからない問題が見つかるとは思いません。

于 2013-09-24T05:47:32.077 に答える