37

インタラクティブなアプリケーションで、CPU を大量に消費するマルチタスク可能なジョブを管理する必要があります。背景として、私の特定のアプリケーションはエンジニアリング設計インターフェースです。ユーザーがモデルのさまざまなパラメーターやオプションを微調整すると、複数のシミュレーションがバックグラウンドで実行され、完了時に結果が表示されます。ユーザーがまだ値を編集している可能性もあります。複数のシミュレーションにはさまざまな時間がかかるため (ミリ秒のものもあれば、5 秒かかるものもあれば、10 分かかるものもあります)、基本的にはフィードバックをできるだけ早く表示することですが、多くの場合、以前に開始されたが不要になったジョブは中止されます。ユーザーの変更のうち、既にそれらが無効になっています。ユーザーの変更が異なれば、異なる計算が無効になる可能性があるため、いつでも 10 の異なるシミュレーションを実行できます。

この種のアプリケーションを処理するためのコード レベルの方法は、ある種のマルチスレッド ジョブ キューであると確信しています。これには、実行のためにジョブを送信する機能、タスクの優先度を設定する機能、ジョブが完了するのを待つ機能、依存関係を指定する機能 (このジョブを実行しますが、ジョブ X とジョブ Y が完了した後でのみ)、いくつかの基準に適合するジョブのサブセットをキャンセルする機能、何をクエリする機能が含まれます。ジョブが残り、ワーカー スレッドの数と優先順位が設定されます。また、マルチプラットフォームのサポートも非常に便利です。

これらはソフトウェアの新しいアイデアや要望ではありませんが、私はアプリケーションの初期設計段階にあり、そのようなタスクを管理するためにどのライブラリを使用するかを選択する必要があります。私は過去に C で大まかなスレッド マネージャーを作成しましたが (これは通過儀礼だと思います)、自分の以前のハックではなく、最新のツールを使用して作業を行いたいと考えています。

最初に考えたのは、OpenMPを実行することですが、それが私が望むものかどうかはわかりません。OpenMP は、細かいレベルでの並列化、ループの自動展開などに最適です。マルチプラットフォームである一方で、#pragmas でコードに侵入します。しかし、ほとんどの場合、大規模なタスクを管理するようには設計されていません。特に、保留中のジョブをキャンセルしたり、依存関係を指定したりします。可能ですが、エレガントではありません。

Google Chrome では、最も些細なタスクでもこのようなジョブ マネージャーを使用していることに気付きました。設計の目標は、ユーザー インタラクション スレッドを可能な限り軽量かつ機敏に保つことであるように思われるため、非同期で生成できるものはすべてそうする必要があります。Chrome のソースを見ると、これは一般的なライブラリではないように見えますが、設計が非同期起動を使用して対話を高速に保つ方法を見るのは興味深いことです。これは、私がやっていることと似てきています。

まだ他のオプションがあります:

Surge.Act:ジョブを定義するための Boost のようなライブラリ。OpenMP で構築されていますが、依存関係の連鎖が可能で、これは素晴らしいことです。クエリを実行したり、ジョブをキャンセルしたりできるマネージャーがいるような気がしないようです。古いプロジェクトなので、それに依存するのは怖いです。

Job Queueは私が考えているものにかなり近いですが、これは 5 年前の記事であり、サポートされているライブラリではありません。

Boost.threadsには、プラットフォームに依存しない優れた同期がありますが、それはジョブ マネージャーではありません。POCOは、タスクを起動するための非常にクリーンな設計を備えていますが、タスクをチェーンするための完全なマネージャーではありません。(私はPOCOを過小評価しているかもしれませんが)。

そのため、利用可能なオプションはありますが、私は満足しておらず、自分のライブラリをもう一度ロールアップしたいという衝動を感じています. しかし、私はむしろすでに存在するものを使用したいと思います。検索した後でも(ここSOとネットで)、適切に感じるものは何も見つかりませんでしたが、これはしばしば必要とされる一種のツールであるに違いないので、コミュニティライブラリまたは少なくとも一般的なデザインが確実にあります. SO にはjob queuesに関する投稿がいくつかありましたが、適合するものは何もありません。

ここでの私の投稿は、私が見逃した既存のツール、および/またはそのような独自のマルチスレッド ジョブ キューをどのように展開したかをすべて質問することです。

4

11 に答える 11

18

私たちはあなたと同様の要件を満たすために独自のジョブキューシステムを構築する必要がありました(UIスレッドは常に33ms以内に応答する必要があり、ジョブは15〜15000msで実行できます)。 。

残念ながら、私たちのコードはプロプライエタリと同じくらいプロプライエタリですが、最も顕著な機能のいくつかを提供できます。

  • プログラムの開始時に、コアごとに1つのスレッドを開始します。それぞれがグローバルジョブキューから作業をプルします。ジョブは、関数オブジェクトと関連データのグロブで構成されます(実際にはfunc_ptrとvoid *の詳細)。高速クライアントループであるスレッド0はジョブでの作業を許可されていませんが、残りは可能な限り取得します。
  • ジョブキュー自体は、ロックフリーの単一リンクリストなどのロックレスデータ構造である必要があります(Visual Studioには1つ付属しています)。ミューテックスの使用は避けてください。キューの競合は驚くほど高く、ミューテックスの取得にはコストがかかります。
  • ジョブに必要なすべてのデータをジョブオブジェクト自体にパックします。ジョブからメインヒープにポインタを戻さないようにします。メインヒープでは、ジョブとロックの間の競合や、その他の遅くて煩わしいものすべてに対処する必要があります。たとえば、すべてのシミュレーションパラメータはジョブのローカルデータブロブに入れる必要があります。結果の構造は、明らかにジョブよりも長持ちするものである必要があります。これは、a)実行が終了した後でもジョブオブジェクトにぶら下がる(メインスレッドからコンテンツを使用できるようにする)か、b)のいずれかで対処できます。各ジョブに特別に結果構造を割り当て、ジョブのデータオブジェクトにポインタを詰め込みます。結果自体はジョブに存在しませんが、これにより、ジョブに出力メモリへの排他的アクセスが効果的に与えられるため、ロックをいじくり回す必要はありません。

  • 実際、私は少し上を単純化しています。どのジョブがどのコアで実行されるかを正確に振り付けする必要があるため、各コアは独自のジョブキューを取得しますが、それはおそらく不要です。

于 2009-02-20T03:14:08.950 に答える
5

Boost.threads に基づいて、自分で作成しました。ごくわずかなコードを書くだけで、これほど大きな成果が得られたことに、私はかなり驚きました。事前に作成されたものが見つからない場合は、恐れずに自分で作成してください。Boost.threads と、独自のスレッドを作成してからの経験との間では、覚えているよりも簡単かもしれません。

事前に作成されたオプションについては、 Chromiumが非常にフレンドリーにライセンスされていることを忘れないでください。そのため、そのコードに独自の汎用ライブラリを展開できる場合があります。

于 2009-02-19T14:01:37.527 に答える
4

Microsoft は、Concurrency Runtime、Parallel Pattern Library、Asynchronous Agents Library と呼ばれる Visual Studio 2010 の次期バージョン向けの一連のテクノロジに取り組んでおり、おそらく役立つでしょう。コンカレンシー ランタイムは、ポリシー ベースのスケジューリングを提供します。つまり、複数のスケジューラー インスタンスを管理および構成できます (スレッド プールに似ていますが、インスタンス間のアフィニティ化と負荷分散が行われます)。並列パターン ライブラリは、タスク ベースのプログラミングと STL のような並列ループを提供します。プログラミングモデル。エージェント ライブラリは、アクター ベースのプログラミング モデルを提供し、同時データ フロー パイプラインの構築、つまり上記の依存関係の管理をサポートしています。残念ながら、これはまだリリースされていないため、チームのブログで読むことができますまたは、channel9 でいくつかのビデオをご覧ください。ダウンロード可能な非常に大きな CTP もあります。

今すぐ解決策を探しているなら、Intel の Thread Building Blocks と boost のスレッド化ライブラリはどちらも優れたライブラリであり、現在利用可能です。JustSoftwareSolutionsは、C++0x ドラフトに一致する std::thread の実装をリリースしました。もちろん、細粒度ループ ベースの並列処理を検討している場合、OpenMP は広く利用できます。

他の人がほのめかしたように、実際の課題は、作業を正しく識別して同時実行に適したタスクに分解し (つまり、保護されていない共有状態がない)、それらの間の依存関係を理解し​​、ボトルネックで発生する可能性のある競合を最小限に抑えることです (ボトルネックが保護されているかどうか)。状態を共有するか、ワーク キューのディスパッチ ループの競合が少ないかロックフリーであることを確認します)...そして、実装の詳細をコードの残りの部分に漏らさずにスケジュールすることなくこれを行います。

-リック

于 2009-02-20T07:18:17.083 に答える
3

スレッドプールのようなものはあなたに役立ちますか?これはboost::threadsに基づいており、基本的に、ワーカー関数をプールされたスレッドに渡す単純なスレッドタスクキューを実装します。

于 2009-02-19T17:29:18.643 に答える
2

フローベースプログラミングを検討することをお勧めします。これは、非同期コンポーネント間でストリーミングされるデータチャンクに基づいています。ドライバーにはJavaバージョンとC#バージョンに加えて、事前にコード化されたコンポーネントがいくつかあります。これは本質的にマルチスレッドです。実際、コンポーネント内にあるのはシングルスレッドコードだけですが、標準のスケジューリングルールにタイミング制約を追加することもできます。必要なレベルには細かすぎるかもしれませんが、ここで使用できるものがあるかもしれません。

于 2009-02-19T21:33:41.980 に答える
1

boost::futureを見てください (ただし、このディスカッション提案も参照してください)。これは、並列処理の非常に優れた基盤のように見えます (特に、A と B に依存する C の状況に対して優れたサポートを提供しているようです)。 .

私は OpenMP を少し調べましたが、(あなたと同じように) Fortran/C 数値コード以外でうまく機能するとは確信していませんでした。Intel のThreading Building Blocksは、私にとってより興味深いものでした。

それに関して言えば、boost::thread の上に独自のロールを作成するのはそれほど難しくありません。[説明: スレッドファーム(ほとんどの人はそれをプールと呼ぶ) は、ファンクタ (タスクまたはジョブ)のスレッドセーフなキューから作業を引き出します。使用例については、テストベンチマークを参照してください。(オプションで) 優先度のあるタスクをサポートするための追加の複雑さ、および実行中のタスクがより多くのタスクを作業キューに生成できる場合 (これにより、すべての作業が実際にいつ完了したかを知ることが少し問題になります。「保留中」への参照ケースを処理できるものです)。いずれにせよ、いくつかのアイデアを提供するかもしれません。]

于 2009-02-19T14:01:46.577 に答える
1

分散リソース マネージャーはたくさんあります。お客様の要件をほぼすべて満たすソフトウェアは、Sun Grid Engineです。SGE は、世界最大のスーパーコンピューターのいくつかで使用されており、活発に開発されています。

TorquePlatform LSF、およびCondorにも同様のソリューションがあります。

独自のものを作りたくなるかもしれませんが、上記のすべてに十分な機能があります。

于 2009-02-20T08:38:21.667 に答える
1

Intel Thread Building Blocksを参照してください。バージョン 2 では、それはオープン ソースです。

于 2009-02-20T06:04:38.650 に答える
0

あなたがC++ライブラリを探しているかどうかはわかりませんが(私はあなたがそうだと思います)、Java7用のDougLeaのFork/ Joinフレームワークはかなり気の利いたものであり、まさにあなたが望むことを実行します。おそらく、C ++で実装するか、事前に実装されたライブラリを見つけることができるでしょう。

詳細はこちら: http ://artisans-serverintellect-com.si-eioswww6.com/default.asp?W1

于 2009-02-20T02:54:39.213 に答える
0

おそらくパンチには少し遅れていますが、ThreadWeaver もご覧ください: http://en.wikipedia.org/wiki/ThreadWeaver

于 2009-08-07T22:39:34.380 に答える