PNGファイルのディレクトリで動作する5つのpngout.exeプロセスを生成することにより、PNGファイルを最適化しています。pngout はシングル スレッドであるため、大幅な高速化が実現します。画像によっては、最適化に 30 秒以上かかるものもありますが、通常は 5 秒未満です。問題:
- ファイル 1 は大きく、2 ~ 5 は小さく、合計 50 ファイルですが、残りの詳細は関係ありません。
- 最初の 5 つの pngout プロセスが正常に生成され、動作を開始します
- 10秒以内に2-5回退出
- 1 45 秒かかります
- 4 つのスレッドが空いているにもかかわらず、この間、新しい 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 つのプロセスが実行されています。
後半の編集:ここからの StreamGobblerは、おそらくより適切です。