6

テストプログラムの2つのバリエーションを比較しています。どちらもForkJoinPool、4コアのマシンで4スレッドで動作しています。

「モード1」では、エグゼキュータサービスのようにプールを使用します。たくさんのタスクをに投げ込みExecutorService.invokeAllます。通常の固定スレッドエグゼキュータサービスよりもパフォーマンスが向上します(Luceneへの呼び出しがあり、そこでI / Oが実行されます)。

ここには分割統治法はありません。文字通り、私はします

ExecutorService es = new ForkJoinPool(4);
es.invokeAll(collection_of_Callables);

「モード2」では、単一のタスクをプールに送信し、そのタスクでForkJoinTask.invokeAllを呼び出してサブタスクを送信します。したがって、から継承するオブジェクトがRecursiveActionあり、それがプールに送信されます。そのクラスのcomputeメソッドで、も継承するinvokeAllのクラスのオブジェクトのコレクションでを呼び出します。テストの目的で、最初のオブジェクトを一度に1つずつ送信します。スレッドの呼び出しは、ただ座ってブロックするのではなく、サブタスクの1つを自分自身で取得するため、4つのスレッドすべてがビジーであることがわかります。それがそのように機能しないかもしれないいくつかの理由を考えることができます。RecursiveActioninvokeAll

VisualVMで、モード2で監視している場合、ほとんどの場合、1つのスレッドが待機しています。私が期待しているのは、invokeAllを呼び出すスレッドが、ただじっと座っているだけでなく、呼び出されたタスクの1つですぐに機能することです。これは、通常のスレッドプールでこのスキームを試した結果として生じるデッドロックよりも確かに優れていますが、それでもどうでしょうか。他の何かが提出された場合に備えて、1つのスレッドを保留していますか?そして、もしそうなら、なぜモード1で同じ問題を起こさないのですか?

これまで、Java1.6のブートクラスパスに追加されたjsr166jarを使用してこれを実行してきました。

4

2 に答える 2

3

ForkJoinTask.invokeAllはすべてのタスクをフォークしていますが、リストの最初にあります。それ自体が実行する最初のタスク。次に、他のタスクに参加します。スレッドはプールに解放されません。ご覧のとおり、他のタスクを完了するのはスレッドブロッキングです。

于 2012-03-14T18:24:04.477 に答える
3

invokeAllフォーク結合プールの一般的な使用法は、1つのタスクをフォークし、別のタスクを(その実行中のスレッドで)計算することです。フォークしないスレッドは、計算後に参加します。仕事を盗むことは、両方のタスクのコンピューティングに伴います。各タスクが計算するとき、それ自体のサブタスクをフォークすることが期待されます(いくつかのしきい値に達するまで)。

どのinvokeAllが呼び出されているかはわかりませんRecursiveAction.compute()が、2つのRecursiveActionを実行するinvokeAllの場合、一方をフォークし、もう一方を計算して、フォークされたタスクが終了するのを待ちます。

ExecutorServiceの各タスクは単にキュー上で実行可能であるため、これはプレーンなエグゼキュータサービスとは異なります。ExecutorServiceの2つのタスクが別のタスクの結果を知る必要はありません。これがFJプールの主なユースケースです。

于 2012-03-15T03:03:14.033 に答える