4

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は、おそらくより適切です。

4

1 に答える 1

0

スレッドが不足しています。スレッドを適切に管理するには、JavaのスリープまたはIOを実行する必要があります。それはJVMの障害ではなく、オペレーティングシステムのスレッド化が壊れています。

于 2011-07-13T15:42:33.523 に答える