4

現在、Javaアプリでマルチスレッドを使用してパフォーマンスを調整しようとしています。マルチCPUコアに分割したい長期実行のシリアルタスクがあります。

基本的に、100.000アイテム/やることのリストがあります。

今の私の質問は、次のことを行う方が良いということです。

オプション1(擬似コード):

for(i = 0; i < 100000; i++){
  threadpool.submit(new MyCallable("1 thing to do"))
}

これにより、スレッドプールのキュー(現在のLinkedBlockingQueue)に100000の実行可能ファイル/呼び出し可能オブジェクトが追加されます。

または、より良い方法です: オプション2(擬似コード)

for(i = 0; i < 4; i++){
  threadpool.submit(new MyCallable("25000 things to do"))
}

すでにオプション1を試しましたが、パフォーマンスの向上は見られませんでしたが、複数のスレッドが狂ったように機能し、4つのCPUコアが使用されていることがはっきりとわかります。しかし、私の感じでは、多くのタスクがあるため、オプション1にはいくらかのオーバーヘッドがあります。オプション2はまだ試していませんが、オーバーヘッドが少ないのでスピードアップできると思います。基本的に、リストを100000個の単一アイテムではなく、4つの大きなチャンクに分割しています。

これについて何か考えはありますか?

ありがとう

4

5 に答える 5

3

あなたの分析は正しいです:アイテムをバッチ処理する際のコスト(メモリ、コンテキストスイッチング、および一般的な命令数)が少なくなります-少なくとも、一般的に言えば。

ただし、個々のタスクが大きくなるにつれて、これはますます関連性が低くなります。スレッドプールのオーバーヘッドやオブジェクトの作成ではなく、すでに99%の時間を作業に費やしている場合は、この方法で残っている1%しか最適化できません。

于 2012-05-30T07:09:07.617 に答える
3

重要なのは、コンテキスト切り替えの量を最小限に抑え、計算に費やされるタスクごとの作業量を最大化することです。実際問題として、タスクがコンピューティングの場合、物理 CPU の数を超えても役に立ちません。タスクが実際に多くの I/O と I/O 待機を行う場合は、多くのタスクを用意して、1 つのブロックが発生したときに常に「準備完了」のタスクが多数存在するようにします。

本当に 25000 のやるべきことがあり、それが計算である場合、私はおそらく 32 のスレッド (あなたが持っているよりも多くの CPU を持っていますが、余分なオーバーヘッドはそれほど多くありません) をセットアップし、それぞれに 10 から 50 単位の作業を分配します。それらのユニットが比較的小さい場合。

于 2012-05-30T07:14:27.220 に答える
1

まあ、それはあなたのユースケースに依存します。

パフォーマンスに関しては、スレッド数が少ないよりも、作業のチャンクが大きい方が優れていると思います。コンテキストの切り替えが少なくなるため、CPU サイクルと RAM を節約できます。

タスクの数が少ない場合、これはあまり問題にならないかもしれませんが、そうです、10000 のスレッドがある場合は問題になります。

于 2012-05-30T07:11:02.187 に答える