PNGファイルのディレクトリで作業するために5つのpngout.exeプロセスを作成して、PNGファイルを最適化しています。 pngoutはシングルスレッドなので、結果としてスピードアップが大きくなります。一部の画像は、30秒以上で最適化するのに時間がかかりますが、標準は< 5秒です。問題:長時間の計算により、ExecutorServiceは新しい仕事の割り当てを中止します。
- ファイル1は大きく、ファイルサイズは2〜5、合計で50ファイルですが、残りの部分は無関係です。
- まず5つのpngoutプロセスが正常に産卵としたら4つのスレッドを無料
- を有しているにも関わらず
- 2-5終了10秒以内に
- 1が45秒
- んが新しいpngoutプロセスは、この中に生成されていないを取る作業を開始します1の完了、別の5つのプロセスが生成されます。
コード:
private final ExecutorService pool = Executors.newFixedThreadPool(5);
/*^instance var, below is in method */
CompletionService<Boolean> comp = new ExecutorCompletionService<Boolean>(pool);
List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
for (int i = 0; i < files.length; i++) {
File infile = files[i];
File outfile = new File(outdir, infile.getName());
tasks.add(new CrushTask(crusher, infile, outfile));
}
for (Callable<Boolean> t : tasks)
comp.submit(t);
for (int i = 0; i < files.length; i++) {
try {
boolean res = comp.take().get();
System.out.println(res);
} catch (Exception e) {
e.printStackTrace();
}
}
すべてのファイルが適切に最適化されて、コードの一部が動作します。問題は、大きな画像を待つことによって、プロセス全体が大幅に遅くなることです。私はシングルスレッドの時間に比べてわずか40%の改善しか得ていません。
私は間違っていますか?
編集:本当に醜いコードを使用して問題を修正しました。問題は、私が産んでいたプロセスの終了値を取得することです(完了した時点と成功したかどうかを知るために)waitForを呼び出すと永遠にハングするので、何もせずにstdoutを読み込んでいました。しかし、明らかにInputStreamsを使用すると、スレッドがチョークします。だからではなく、これを使用しての、プロセスの終了値を取得する
:
private static int discardStdOut(Process proc) throws IOException {
final InputStream is = proc.getInputStream();
try {
while (is.read() != -1)
continue;
return proc.exitValue();
} finally {
close(is);
}
}
私はこの総コード使用しています:
private static int discardStdOut(Process proc) {
int ret = -1;
while (true) {
try {
ret = proc.exitValue();
break;
} catch (IllegalThreadStateException e) {
try {
Thread.sleep(100);
} catch (InterruptedException e2) {
e2.printStackTrace();
}
}
}
return ret;
}
をそれは総ですが、今のシステムは常に罰金と作品5つのプロセスが実行されています。
late編集:StreamGobblerからhereがおそらくより適切です。
ファイル変数の定義は何ですか?それは完全な50のファイルですか? –
files変数は、50個すべての入力PNGファイルを含む配列です。 –
@Aleksei Vasilievは、1が完了する前にスレッドダンプを取得するのに便利かもしれません。 –