4

プログラムを高速化するためにマルチスレッドを使用したいのですが、どちらの方法が最適かわかりません。

10000の小さなタスクがあるとすると、そのうちの1つを完了するのにたった0.1秒しかかかりません。これで、12コアのCPUができました。これを高速化するために、12スレッドを使用したいと思います。

私の知る限り、2つの方法があります。

1.タスクプール

常に12のスレッドが実行されており、それぞれが現在の作業を終了した後、タスクプールから1つの新しいタスクを取得します。

2.個別のタスク

10000のタスクを12の部分に分割し、各スレッドが1つの部分で機能するようにします。

問題は、タスクプールを使用する場合、複数のスレッドがタスクプールにアクセスしようとすると、ロック/ロック解除に時間の無駄になることです。ただし、一部のスレッドは早く終了するため、2番目の方法は理想的ではありません。合計時間は、最も遅いスレッドによって異なります。

この種の仕事や他の最善の方法をどのように扱っているのでしょうか。ありがとうございました。

編集:10000という数字は単なる例であり、実際には1e8以上のタスクである可能性があり、タスクあたり0.1も平均時間であることに注意してください。

EDIT2:すべての回答に感謝します:]オプションの種類を知っておくのは良いことです。

4

5 に答える 5

5

したがって、2つのアプローチの中間の1つは、それぞれ100タスクの100バッチに分割し、コアにタスクプールから一度に100タスクのバッチを選択させることです。

おそらく、単一のタスクの単一のコアで実行時間のランダム性をモデル化し、ミューテックスのロック時間の見積もりを取得すると、最適なバッチサイズを見つけることができる場合があります。

しかし、あまり多くの作業をしなくても、少なくとも次の補題があります。

最も遅いスレッドは、他のスレッドよりも最大100 * .1=10秒しかかかりません。

于 2012-04-03T22:38:53.013 に答える
3

ここでは、タスクプールが常に最良のソリューションです。それは最適な時間であるだけでなく、コードの理解度でもあります。コアと同じ数のサブタスクを持つという完全に無関係な基準にタスクを強制的に準拠させないでください。タスクは(一般的に)それとは関係がなく、マシンを変更する場合など、そのような分離はスケーリングされません。 。最終的なタスクのサブタスクで結果を組み合わせるにはオーバーヘッドが必要であり、一般的に簡単なタスクを困難にします。

ただし、タスクプールのロックの使用について心配する必要はありません。 必要だと判断した場合は、ロックフリーキューを利用できます。しかし、最初にそれを決定します。時間が気になる場合は、タスクをスピードアップする適切な方法を使用し、最大の利益が得られる場所に努力してください。コードのプロファイルを作成します。なぜあなたのタスクは0.1秒かかるのですか?彼らは非効率的なアルゴリズムを使用していますか?ループ展開のヘルプはできますか?プロファイリングを通じてコード内のホットスポットを見つけた場合、ロックが最も心配が少ないことに気付くかもしれません。そして、すべてが可能な限り高速に実行されていることがわかり、ロックを解除するのに1秒余分にかかる場合は、お気に入りの検索エンジンでインターネットで「ロックフリーキュー」と「ウェイトフリーキュー」を検索してください。コンペアアンドスワップにより、アトミックリストが簡単になります。

于 2012-04-04T16:01:46.767 に答える
2

質問で提案された両方の方法は、互いに同様にうまく機能します(タスクの期間が予測可能で比較的長い単純なケースでは)。ターゲットシステムのタイプがわかっていて利用可能な場合(そしてパフォーマンスが本当に最大の関心事である場合)、プロトタイピングと測定に基づいてアプローチを選択する必要があります。

コアの数と一致するスレッドの最適な数について、必ずしも自分自身を害する必要はありません。これが通常のサーバーまたはデスクトップシステムの場合、さまざまなシステムプロセスがときどき開始され、12個のスレッドがプロセッサ間でさまざまに変動し、メモリキャッシュに悪影響を与える可能性があります。

また、チェックする必要のある重要な非測定要素もあります。これらの小さなタスクを実行するには、リソースが必要ですか。これらのリソースは、追加の潜在的な遅延(ブロッキング)または競争を課しますか?CPUパワーを奪い合う追加のアプリはありますか?さまざまな実行環境、タスクタイプ、またはユーザーインタラクションモデルに対応するために、アプリケーションを拡張する必要がありますか?

すべての答えが否定的である場合、ここにあなたが測定して検討することができるいくつかの追加のアプローチがあります。

  • 10または11スレッドのみを使用してください。わずかな速度低下、またはわずかな高速化が見られます(追加のコアは、OSプロセスにサービスを提供するため、残りのスレッドの親和性は12スレッドと比較してより安定します)。システム上で同時に行われる対話型アクティビティでは、応答性が大幅に向上します。

  • 正確に12個のスレッドを作成しますが、スレッドとプロセッサの間に1-1マッピングを課すために、それぞれに異なるプロセッサアフィニティマスクを明示的に設定します。これは、CPUと共有メモリ以外のリソースが関係していない最も単純なほぼアカデミックなケースに適しています。プロセス間でのスレッドの慢性的な移行は見られません。欠点は、特定のマシンに密接に結合されたアルゴリズムです。別のマシンでは、動作が非常に悪く、まったく終了しない可能性があります(スレッドの1つを永久にブロックする無関係のリアルタイムタスクのため)。

  • 12個のスレッドを作成し、タスクを均等に分割します。負荷の40%を超えたら、また80%を超えたら、各スレッドに独自の優先度をダウングレードさせます。これにより、プロセス内の負荷分散が改善されますが、アプリケーションが他のCPUバウンドプロセスと競合している場合は、動作が低下します。

于 2012-04-04T05:28:38.303 に答える
1

100ms/タスク-そのまま積み上げます-プールのオーバーヘッドは重要ではありません。

OTOH ..

1E8タスク@0.1秒/タスク=10,000,000秒=2777.7r時間=115。7日

これは、火曜日のパッチの再起動の間隔をはるかに超えています。

Linuxでこれを実行する場合でも、ジョブを再開できるように、出力をバッチ処理してディスクにフラッシュする必要があります。

関係するデータベースはありますか?もしそうなら、あなたは私たちに言ったはずです!

于 2012-04-03T22:49:25.337 に答える
1

各作業スレッドには、1つまたは2つ以下のメモリページの容量を持つ独自の小さなタスクキューがあります。キューのサイズが小さくなると(容量の半分)、マネージャースレッドにシグナルを送信して、より多くのタスクを追加する必要があります。キューがバッチで編成されている場合、現在のバッチが空でない限り、作業スレッドはクリティカルセクションに入る必要はありません。クリティカルセクションを回避すると、実際の作業に余分なサイクルが発生します。キューごとに2つのバッチで十分です。この場合、1つのバッチが1つのメモリページを使用できるため、キューは2つを使用します。

メモリページのポイントは、スレッドがデータをフェッチするためにメモリ全体をジャンプする必要がないことです。すべてのデータが1つの場所(1つのメモリページ)にある場合は、キャッシュミスを回避できます。

于 2012-04-04T11:41:41.083 に答える