7

ForkJoinPoolを使用 して、CPU を集中的に使用する計算を並列化しようとしています。ForkJoinPool についての私の理解では、タスクを実行できる限り機能し続けるということです。残念ながら、ワーカー スレッドがアイドリング/待機していることを頻繁に観察したため、すべての CPU がビジー状態に保たれているわけではありません。追加のワーカー スレッドを観察することさえありました。

非ブロッキングタスクを厳密に使用しようとしたため、これは予期していませんでした。私の観察は、 ForkJoinPool がスレッドを無駄にしているように見えるのと非常によく似ています。ForkJoinPool に多くのデバッグを行った後、推測があります。

サブタスクのリストに作業を分散するために、invokeAll() を使用しました。invokeAll() が最初のタスク自体の実行を終了した後、他のタスクへの参加を開始します。参加する次のタスクが実行中のキューの一番上に来るまで、これは正常に機能します。残念ながら、追加のタスクに参加せずに非同期で送信しました。私は、ForkJoin フレームワークが最初にこれらのタスクを実行し続けてから、残りのタスクの結合に戻ることを期待していました。

しかし、この方法ではうまくいかないようです。代わりに、待機中のタスクの準備が整うまで (おそらく他のワーカー スレッドによって実行される)、ワーカー スレッドは wait() の呼び出しを停止します。私はこれを確認しませんでしたが、join() を呼び出す一般的な欠陥のようです。

ForkJoinPool は asyncMode を提供します、これはグローバル パラメーターであり、個々の送信には使用できません。しかし、非同期にフォークされたタスクがすぐに実行されるのが好きです。

では、なぜ ForkJoinTask.doJoin() は、準備が整うまで (自分で実行するか、他のユーザーに盗まれるかのいずれか)、キューの一番上にある使用可能なタスクを単純に実行しないのでしょうか?

4

3 に答える 3

3

誰も私の質問を理解していないようなので、数晩のデバッグの後に見つけたものを説明しようとします。

ForkJoinTasks の現在の実装は、すべての fork/join 呼び出しが厳密にペアになっている場合にうまく機能します。開きブラケットによるフォークと閉じブラケットによる結合を示すと、完全なバイナリ フォーク結合パターンは次のようになります。

{([][]) ([][])} {([][]) ([][])}

invokeAll() を使用する場合、次のようにサブタスクのリストを送信することもできます。

{([][][][]) ([][][][]) ([][][][])}

しかし、私がしたことは次のパターンのように見えます:

{([) ([)} ... ]]

これは見栄えが悪い、または fork-join フレームワークの誤用であると主張するかもしれません。ただし、唯一の制約は、タスク完了の依存関係が非循環であることです。そうしないと、デッドロックが発生する可能性があります。[]タスクが()タスクに依存していない限り、問題はありません。問題のある]]は、私がそれらを明示的に待っていないことを単に表現しています。それらはいつか終わるかもしれませんが、それは私には関係ありません (その時点で)。

実際、現在の実装ではインターロックされたタスクを実行できますが、非常に非効率な追加のヘルパー スレッドを生成するだけです。

この欠陥は、現在の join() の実装にあるようです: ) に参加すると、対応する(が実行キューの一番上にあることが期待されますが、 [が見つかり、当惑します。単純に[]を実行してそれを取り除くのではなく、現在のスレッドは (wait() を呼び出して) 他の誰かが予想外のタスクを実行するまで中断します. これにより、パフォーマンスが大幅に低下します.

私の主な意図は、キューが空になった場合にワーカー スレッドが一時停止するのを防ぐために、追加の作業をキューに入れることでした。残念ながら、逆のことが起こります:-(

于 2013-06-06T17:28:03.470 に答える
3

あなたは join() について完全に正しいです。join() の問題点を指摘するこの記事を 2 年前に書きました。

そこで述べたように、フレームワークは、以前のリクエストを完了するまで、新しく送信されたリクエストを実行できません。そして、各 WorkThread は現在のリクエストが終了するまでスチールできず、その結果、wait() が発生します。

表示される追加のスレッドは「継続スレッド」です。join() は最終的に wait() を発行するため、フレームワーク全体が停止しないようにこれらのスレッドが必要です。

于 2013-06-03T13:51:37.690 に答える