[解決済み] fork/joinフレームワークはスレッドプールより優れているか?
質問
新しい fork/join フレームワーク を使う利点は何でしょうか。単純に大きなタスクを N 個のサブタスクに分割し、それらをキャッシュされたスレッドプール ( 実行者 から)キャッシュされたスレッドプールに送信し、各タスクが完了するのを待つという方法よりも優れているのでしょうか?フォーク/結合の抽象化を使用することで、問題がどのように単純化されるか、またはソリューションが何年も前からあるものより効率的になるのか、私にはわかりません。
たとえば、並列化されたブラーリング アルゴリズムは チュートリアルの例 はこのように実装することができます。
public class Blur implements Runnable {
private int[] mSource;
private int mStart;
private int mLength;
private int[] mDestination;
private int mBlurWidth = 15; // Processing window size, should be odd.
public ForkBlur(int[] src, int start, int length, int[] dst) {
mSource = src;
mStart = start;
mLength = length;
mDestination = dst;
}
public void run() {
computeDirectly();
}
protected void computeDirectly() {
// As in the example, omitted for brevity
}
}
冒頭で分割し、タスクをスレッドプールに送る。
// source image pixels are in src
// destination image pixels are in dst
// threadPool is a (cached) thread pool
int maxSize = 100000; // analogous to F-J's "sThreshold"
List<Future> futures = new ArrayList<Future>();
// Send stuff to thread pool:
for (int i = 0; i < src.length; i+= maxSize) {
int size = Math.min(maxSize, src.length - i);
ForkBlur task = new ForkBlur(src, i, size, dst);
Future f = threadPool.submit(task);
futures.add(f);
}
// Wait for all sent tasks to complete:
for (Future future : futures) {
future.get();
}
// Done!
タスクはスレッドプールのキューに入り、そこからワーカスレッドが利用可能になると実行されます。分割の粒度が十分で(最後のタスクを特に待つ必要がないように)、スレッドプールに十分な(少なくともプロセッサのN)スレッドがある限り、すべてのプロセッサは計算全体が終了するまで全速力で働きます。
私は何かを見逃しているのでしょうか?fork/join フレームワークを使用することの付加価値は何でしょうか?
どのように解決するのですか?
基本的な誤解は、Fork/Joinの例では、以下のようになります。 ではない 動作を示す 盗む という、ある種の標準的な分割統治に過ぎない。
仕事の盗みとは、このようなものです。労働者Bは自分の仕事を終えました。彼は親切な人なので、周りを見渡すと、労働者Aがまだ一生懸命働いているのを見つけました。彼は散策して尋ねます: "ヘイ、若者よ、私はあなたに手を貸すことができます,quot;クール、私は1000ユニットのこのタスクを持っています。これまでのところ、私は655を残して345を終了しました。Bは「よし、早くパブに行けるように始めよう」と言いました。
このように、作業者は実際の作業を開始しても、お互いにコミュニケーションを取らなければなりません。これが例の中で欠けている部分です。
一方、例では、「下請け業者を使う」というようなことしか書かれていません。
作業員A: "くっ、1000単位の仕事がある。俺には多すぎる。この作業は、大きなタスクが10ユニットずつの小さなパケットに分割されるまで続けられます。これが、大きな仕事が10個ずつの小さなパケットに分解され、それを空いている作業者が実行する。しかし、あるパケットが毒薬のようなもので、他のパケットよりもかなり時間がかかるとしたら -- 運が悪いことに、分割フェーズは終了です。
Fork/Joinとタスクの先行分割の間に残る唯一の違いは、これです。前もって分割する場合、ワーク キューは最初からいっぱいです。例:1000個、閾値は10なので、キューには100個のエントリーがあります。これらのパケットはスレッドプールメンバーに配布されます。
Fork/Joinはより複雑で、キュー内のパケット数をより少なく保とうとするものです。
- ステップ1: (1...1000)を含む1つのパケットをキューに入れる
- ステップ2: 一人のワーカーがパケット(1...1000)をポップして、二つのパケットに置き換えます。(1...500)と(501...1000)の2つのパケットに置き換えます。
- ステップ3: 1人のワーカーがパケット(500...1000)をポップし、(500...750)と(751...1000)をプッシュします。
- ステップn スタックにはこれらのパケットが含まれています。(1..500), (500...750), (750...875)... (991..1000)
- ステップ n+1 です。パケット(991..1000)がポップされ実行される
- ステップn+2: パケット(981..990)がポップされ、実行されます。
- ステップ n+3: パケット (961..980) がポップされ、(961...970) と (971...980) に分割されます。 ....
Fork/Joinではキューが小さく(例では6)、quot;split"とquot;work"のフェーズはインターリーブされていることが分かります。
複数のワーカーが同時にポッピングとプッシュを行う場合、もちろん相互作用はそれほど明確ではありません。
関連
-
Java Exceptionが発生しました エラー解決
-
javaで非静的な解を静的な参照にすることができない
-
javaの模造品QQ WeChatのチャットルーム
-
VMの初期化中にエラーが発生しました java/lang/NoClassDefFoundError: java/lang/Object
-
xxx:jarのアーティファクトディスクリプタの読み込みに失敗した問題は解決しました。
-
node js npm gruntインストール、elasticsearch-head 5.Xインストール
-
javaコンパイル時のエラー:不正な文字 '\ufeff' に対する解決策です。
-
Eclipse起動エラー:javaは起動したが、終了コード=1を返した(ネット上の様々な落とし穴)
-
[解決済み] Javaの「for each」ループはどのように機能するのですか?
-
[解決済み] Java 8 の並列ストリームにおけるカスタムスレッドプール
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JDKの設定時にjava.dllが見つからない、java SE Runtime Environmentが見つからない問題が発生しました。
-
プロジェクトの依存関係を解決できなかった 解決
-
JQuery DataTable 详解
-
サーブレットクラスのインスタンス化エラーの解決法
-
エラーの解決方法 jarfile XXX.jarにアクセスできません。
-
Spring BootのテストメソッドFailed to load ApplicationContextの問題を解決する
-
Javaエラーメッセージがenclosingクラスでない
-
Eclipse起動エラー:javaは起動したが、終了コード=1を返した(ネット上の様々な落とし穴)
-
起動時にEclipseエラーが発生しました。起動中に内部エラーが発生しました。java.lang.NullPoin: "Javaツーリングの初期化 "中に内部エラーが発生しました。
-
ローカルリソースのロードが許可されていない場合の解決策