11

私の会社は現在、サードパーティのシミュレーションプログラム(自然災害リスクモデリング)を実行しています。このプログラムは、ディスクからギガバイトのデータを吸い上げ、数日間クランチして結果を生成します。間もなく、これをマルチスレッドアプリとして書き直して、数日ではなく数時間で実行するように求められます。変換が完了するまでに約6か月かかると予想しており、単独で作業します。

これを実行するための24プロシージャボックスがあります。元のプログラム(C ++で書かれていると思います)のソースにアクセスできますが、現時点では、プログラムがどのように設計されているかについてはほとんどわかりません。

これに取り組む方法についてアドバイスが必要です。私は経験豊富なプログラマーですが(約30年、現在C#3.5で作業しています)、マルチプロセッサ/マルチスレッドの経験はありません。必要に応じて、新しい言語を学びたいと思っています。言語、学習リソース、本、建築ガイドラインに関する推奨事項を探しています。等

要件:WindowsOS。多くのサポートと優れた学習リソースを利用できる商用グレードのコンパイラ。派手なGUIは必要ありません。おそらく、構成ファイルから実行され、結果がSQLServerデータベースに格納されます。

編集:現在のアプリはC ++ですが、私はほぼ確実にその言語を書き直しに使用しません。誰かが追加したC++タグを削除しました。

4

16 に答える 16

17

数値プロセスシミュレーションは、通常、単一の離散化された問題グリッド(たとえば、地球の表面ガスやほこりの雲)で実行されます。これにより、通常、単純なタスクファーミングや同時実行アプローチが除外されます。これは、物理空間の領域を表す一連のプロセッサに分割されたグリッドが、一連の独立したタスクではないためです。各サブグリッドのエッジにあるグリッドセルは、論理空間で隣接している他のプロセッサに格納されているグリッドセルの値に基づいて更新する必要があります。

ハイパフォーマンスコンピューティングでは、シミュレーションは通常、 MPIまたはOpenMPのいずれかを使用して並列化されます。MPIは、 C、C ++、FortranPythonC#などの多くの言語のバインディングを備えたメッセージパッシングライブラリです。OpenMPは、共有メモリマルチプロセッシング用のAPIです。一般に、MPIはOpenMPよりもコーディングが難しく、侵襲性がはるかに高くなりますが、柔軟性もはるかに高くなります。OpenMPはプロセッサ間で共有されるメモリ領域を必要とするため、多くのアーキテクチャには適していません。ハイブリッドスキームも可能です。

このタイプのプログラミングには、独自の特別な課題があります。競合状態デッドロックライブロック、および並行プログラミングの他のすべての喜びと同様に、プロセッサグリッドのトポロジ(物理プロセッサ間で論理グリッドを分割する方法)を考慮する必要があります。並列スピードアップはプロセッサ間の通信量の関数であり、それ自体が分解されたグリッドのエッジの全長の関数であるため、これは重要です。プロセッサを追加すると、この表面積が増加し、通信オーバーヘッドの量が増加します。粒度を上げる最終的には法外になります。

他の重要な考慮事項は、並列化できるコードの比率です。アムダールの法則は、理論的に達成可能な最大の高速化を規定しています。コードを書き始める前に、これを見積もることができるはずです。

これらの事実は両方とも、実行できるプロセッサの最大数を制限するために共謀します。スイートスポットはあなたが思っているよりかなり低いかもしれません。

あなたがそれを手に入れることができるならば、私は本ハイパフォーマンスコンピューティングをお勧めします。特に、パフォーマンスのベンチマークとチューニングに関する章は貴重です。

主要な問題をカバーする並列コンピューティングの優れたオンライン概要は、Lawerence LivermoreNationalLaboratoryからのこの紹介です。

于 2009-12-14T19:09:36.740 に答える
12

マルチスレッドプロジェクトでの最大の問題は、スレッド間で表示される状態が多すぎることです。特に、キャッシュの一貫性、弱一貫性のメモリなどの問題があるマルチプロセッサ環境では、安全でない方法でデータを読み取ったり変更したりするコードを書くのは簡単すぎます。場に出るかもしれません。

競合状態のデバッグは明らかに不快です。

たとえば、ネットワーク上の複数のマシンに作業を分散することを検討している場合と同じように設計にアプローチします。つまり、並行して発生する可能性のあるタスク、各タスクへの入力、各タスクの出力を特定します。また、特定のタスクを開始する前に、どのタスクを完了する必要があるか。演習のポイントは、データが別のスレッドに表示される各場所、および新しいスレッドが生成される各場所を慎重に検討することです。

このような初期設計が完了すると、データの所有権が明確に分割され、所有権が取得/譲渡されるポイントが明確になります。したがって、マルチスレッドが提供する可能性(安価な共有データ、安価な同期、ロックレス共有データ構造)を安全に利用できる非常に良い立場になります。

于 2009-12-14T17:14:12.573 に答える
7

ワークロードを依存しない作業のチャンクに分割できる場合(つまり、データセットをビット単位で処理でき、データの依存関係があまりない場合)、スレッドプール/タスクメカニズムを使用します。おそらく、Javaのjava.util.concurrentに相当するものとしてC#が持っているものは何でも。データからワークユニットを作成し、それらをタスクにラップしてから、スレッドプールにタスクをスローします。

もちろん、ここではパフォーマンスが必要かもしれません。元の処理コードカーネルをそのまま維持できる場合は、C#アプリケーション内から呼び出すことができます。

コードに多くのデータ依存関係がある場合、スレッド化されたタスクに分割するのは非常に難しいかもしれませんが、アクションのパイプラインに分割することはできるかもしれません。これは、スレッド1がデータをスレッド2に渡し、スレッド3から8にデータを渡し、スレッド9にデータを渡すことを意味します。

コードに多くの浮動小数点数学が含まれている場合は、OpenCLまたはCUDAで書き直し、CPUではなくGPUで実行することを検討する価値があるかもしれません。

于 2009-12-14T17:09:49.290 に答える
3

プロジェクトを設計する場合、マルチスレッドを処理するために使用できる手法はたくさんあります。

最も一般的で普遍的なのは、単に「共有状態を回避する」ことです。可能な限り、同じ共有コピーにアクセスさせるのではなく、スレッド間でリソースをコピーします。

低レベルの同期コードを自分で作成している場合は、まったく想定しないことを忘れないでください。コンパイラとCPUの両方がコードを並べ替えて、コードの読み取り時に競合状態やデッドロックが発生する可能性があります。これを防ぐ唯一の方法は、メモリバリアを使用することです。また、最も単純な操作でもスレッドの問題が発生する可能性があることに注意してください。++i通常はアトミックではないほど単純なものであり、複数のスレッドがアクセスするiと、予測できない結果が得られます。もちろん、変数に値を割り当てたからといって、新しい値が他のスレッドに表示される保証はありません。コンパイラは、実際にメモリに書き出すのを延期する場合があります。この場合も、メモリバリアにより、保留中のすべてのメモリI/Oが「フラッシュ」されます。

もし私があなたなら、可能であれば、単純なロック/ミューテックス/モニター/クリティカルセクションよりも高いレベルの同期モデルを使用します。.NET言語やネイティブC++など、ほとんどの言語とプラットフォームで使用できるCSPライブラリがいくつかあります。

これにより、通常、競合状態とデッドロックを検出して修正するのが簡単になり、ばかげたレベルのスケーラビリティが可能になります。ただし、このパラダイムにもある程度のオーバーヘッドが伴うため、各スレッドの作業量は他の手法よりも少なくなる可能性があります。また、アプリケーション全体をこのパラダイム用に特別に構造化する必要があります(したがって、既存のコードに後付けするのは難しいですが、最初から始めるので問題は少なくなりますが、それでもなじみはありません)

別のアプローチはトランザクションメモリかもしれません。これは従来のプログラム構造に適合させるのが簡単ですが、いくつかの制限もあり、そのための多くの製品品質のライブラリを知りません(STM.NETが最近リリースされたので、チェックする価値があるかもしれません。IntelにはC++があります言語に組み込まれたSTM拡張機能を備えたコンパイラー)

ただし、どちらのアプローチを使用する場合でも、作業を独立したタスクに分割する方法と、スレッド間のクロストークを回避する方法について慎重に検討する必要があります。2つのスレッドが同じ変数にアクセスするときはいつでも、潜在的なバグがあります。また、2つのスレッドが同じ変数または同じアドレスの近くにある別の変数(たとえば、配列内の次または前の要素)にアクセスするときはいつでも、データをコア間で交換する必要があり、CPUキャッシュからメモリに強制的にフラッシュされます。 、次に他のコアのキャッシュに読み込みます。これは、パフォーマンスに大きな打撃を与える可能性があります。

ああ、 C ++でアプリケーションを作成する場合は、言語を過小評価しないでください。堅牢なコード、はるかに堅牢でないスレッドコードを記述できるようになる前に、言語を詳細に学習する必要があります。

于 2009-12-14T18:23:06.417 に答える
3

6か月のプロジェクトの場合、最初にこの主題についての良い本を読み始めることは間違いなく報われると思います。WindowsでのJoeDuffyのコンカレントプログラミングをお勧めします。これは私がこの主題について知っている中で最も徹底的な本であり、.NETとネイティブのWin32スレッドの両方をカバーしています。この宝石を発見したとき、私は10年間マルチスレッドプログラムを作成しましたが、それでもほとんどすべての章で知らないことを見つけました。

また、「自然災害リスクモデリング」は多くの数学のように聞こえます。たぶん、IntelのIPPライブラリを見る必要があります。これは、多くの一般的な低レベルの数学および信号処理アルゴリズムのプリミティブを提供します。箱から出してすぐにマルチスレッドをサポートするため、タスクが大幅に簡単になります。

于 2009-12-14T18:50:40.687 に答える
2

この状況で私たちが本当にうまくいったことの1つは、実行する作業を個々のチャンクに分割し、各チャンクのアクションを異なるプロセッサーに分割することです。次に、プロセッサのチェーンがあり、データチャンクはチェーンを個別に処理できます。チェーン内のプロセッサの各セットは、それぞれ複数のスレッドで実行でき、チェーン内の他のプロセッサと比較した独自のパフォーマンスに応じて、多かれ少なかれデータを処理できます。

また、データとアクションの両方をより小さな部分に分割することで、アプリの保守性とテスト性が大幅に向上します。

于 2009-12-14T17:13:45.723 に答える
2

ここで提供できる個別のアドバイスはたくさんあり、すでに何人かの人々がそうしています。ただし、特定の要件(まだ完全には理解していない)でこれをすべて機能させる方法を正確に説明できる人はいないため、今のところHPC(ハイパフォーマンスコンピューティング)を読んで、包括的な概念は明確であり、どの方向があなたのニーズに最も適しているかについてより良い考えを持っています。

于 2009-12-14T17:19:19.003 に答える
2

特にアーランと「アクターモデル」について読んでください。すべてのデータを不変にすると、データの並列化がはるかに簡単になります。

于 2009-12-14T18:12:59.757 に答える
2

使用するモデルは、データの構造によって決まります。データは密結合ですか、それとも緩結合ですか?シミュレーションデータが緊密に結合されている場合は、OpenMPまたはMPI(並列コンピューティング)を検討することをお勧めします。データが緩く結合されている場合は、ジョブプールの方が適している可能性があります...おそらく分散コンピューティングアプローチでも機能する可能性があります。

私のアドバイスは、並行性/並列性のさまざまなモデルに精通するための紹介テキストを入手して読むことです。次に、アプリケーションのニーズを確認し、使用する必要のあるアーキテクチャを決定します。必要なアーキテクチャがわかったら、支援するツールを確認できます。

トピックの紹介として機能するかなり評価の高い本は、「並行性の芸術:並列アプリケーションを作成するためのスレッドモンキーのガイド」です。

于 2009-12-14T21:30:50.083 に答える
1

他のほとんどの回答は、プロジェクトのパーティション化に関する優れたアドバイスを提供します。必要なデータ共有がほとんどなく、並行してクリーンに実行できるタスクを探してください。静的変数やグローバル変数などの非スレッドセーフな構造、またはスレッドセーフではないライブラリに注意してください。私たちが遭遇した最悪のものはTNTライブラリであり、状況によってはスレッドセーフな読み取りさえ許可しません。

すべての最適化と同様に、最初にボトルネックに集中します。これは、スレッド化によって複雑さが増し、不要な場合は回避したいためです。

さまざまなスレッドプリミティブ(ミューテックス、セマフォ、クリティカルセクション、条件など)とそれらが役立つ状況をよく理解する必要があります。

私が付け加えたいのは、C ++を使い続けるつもりなら、boost.threadライブラリを使用して多くの成功を収めているということです。必要なマルチスレッドプリミティブのほとんどを提供しますが、スレッドプールはありません(デッドロックの問題が多数あるため、Google経由で見つけることができる非公式の「ブースト」スレッドプールには注意が必要です)。

于 2009-12-14T18:13:01.143 に答える
1

.NET 4.0には、並行コードの記述を容易にすることを特に目的とした多くの新しいサポートがあるため、これを行うことを検討します。正式なリリース日は2010年3月22日ですが、それ以前はおそらくRTMであり、今すぐ安定したBeta2から始めることができます。

使い慣れたC#を使用することも、マネージC++を使用することもできます。

大まかに言うと、プログラムを個々の作業単位であるSystem.Threading.Tasks.Taskに分割してみてください。さらに、共有状態の使用を最小限に抑え、可能な場合はParallel.For(またはForEach)やPLINQの使用を検討します。

これを行うと、非常に効率的な方法で多くの手間のかかる作業が行われます。これは、Microsoftがますますサポートする方向です。

2:.NET 4.0では、並行コードの記述を容易にすることを特に目的とした多くの新しいサポートがあるため、これを行うことを検討します。正式なリリース日は2010年3月22日ですが、それ以前はおそらくRTMであり、今すぐ安定したBeta2から始めることができます。大まかに言うと、プログラムを個々の作業単位であるSystem.Threading.Tasks.Taskに分割してみてください。さらに、共有状態の使用を最小限に抑え、可能な場合はParallel.ForやPLINQの使用を検討します。これを行うと、非常に効率的な方法で多くの手間のかかる作業が行われます。 1: http: //msdn.microsoft.com/en-us/library/dd321424%28VS.100%29.aspx

于 2009-12-14T18:32:15.427 に答える
1

申し訳ありませんが、ここに悲観的またはより現実的な答えを追加したいと思います。

あなたは時間のプレッシャーにさらされています。6か月の期限があり、このシステムがどの言語で、何を実行し、どのように構成されているかさえわかりません。それが些細な計算でなければ、それは非常に悪いスタートです。

最も重要なこと:あなたはこれまでマルチスレッドプログラミングを行ったことがないと言います。これは私が一度に4つの目覚まし時計を鳴らすところです。マルチスレッドは難しく、正しく実行したいときに習得するのに長い時間がかかります。大幅な速度向上を実現したい場合は、正しく実行する必要があります。TotalViewsデバッガーやIntelsVTuneなどの優れたツールを使用しても、デバッグは非常に厄介です。

次に、別の言語でアプリを書き直したいと言います。とにかく書き直さなければならないほど悪くはありません。完全に再設計することなく、シングルスレッドプログラムを正常に機能するマルチスレッドプログラムに変える可能性はほとんどありません。

しかし、3か月のタイムラインでマルチスレッドと新しい言語(C ++のスキルは何ですか?)を学ぶことは非常に困難です(使い捨てのプロトタイプを作成する必要があるため、タイムスパンを2分の1に短縮します)。

ここでの私のアドバイスは単純で、気に入らないでしょう。マルチスレッディングを今すぐ学びましょう。これは将来必要なスキルセットであるためですが、この仕事はすでに経験のある人に任せてください。プログラムが成功することを気にせず、6か月の支払いを探している場合を除きます。

于 2009-12-18T08:45:34.397 に答える
0

それがまだ言及されているかどうかはわかりませんが、私があなたの立場にある場合、私が今やっていることは(ここに投稿されたすべての回答を読むことを除いて)あなたの好きな(最もよく使われる)言語でマルチスレッドのサンプルアプリケーションを書くことです。

マルチスレッドの経験はあまりありません。私は過去にそれを楽しんで遊んだことがありますが、使い捨てアプリケーションである程度の経験を積むことはあなたの将来の努力に合うと思います。

私はあなたがこの努力で幸運を祈っています、そして私は私がこのような何かに取り組む機会があったことを認めなければなりません...

于 2009-12-14T22:32:42.693 に答える
0

これを作成するテクノロジーが何であれ、並行性に関する必読の本「Javaでの並行プログラミング」をご覧ください。.Netの場合、並行アプリにはretlangライブラリを強くお勧めします。

于 2009-12-14T18:28:27.853 に答える
0

すべてのスレッドが互いに素なプロセスデータのセットで動作し、他の情報がSQLデータベースに格納される可能性がある場合は、C ++で非常に簡単に実行でき、Windowsを使用して新しいスレッドを生成して独自の部分で動作させることができます。 API。SQLサーバーは、DBトランザクションですべてのハード同期の魔法を処理します。そしてもちろん、C ++はC#よりもはるかに高速に動作します。

このタスクのためにC++を確実に改訂し、C ++コードを理解し、既存のコードの効率のバグを探し、マルチスレッド機能を追加する必要があります。

于 2009-12-14T17:11:51.313 に答える
0

この質問にC++のタグを付けましたが、現在C#開発者であると述べているため、C ++とC#のどちらからこの割り当てに取り組むかはわかりません。とにかく、C#または.NET(C ++ / CLIを含む)を使用する場合:次のMSDN記事をブックマークしているので、準備作業の一環としてそれを読むことを強くお勧めします。

同期メソッドを非同期で呼び出す

于 2009-12-14T18:20:12.383 に答える