4

我正在通过生成 5 个 pngout.exe 进程来优化 PNG 文件,以处理 PNG 文件的目录。由于 pngout 是单线程的,这会导致很大的加速。有些图像需要很长时间来优化,超过 30 秒,而标准是 <5 秒。问题:

  • 文件1大,2-5小,共50个文件,其余细节无关。
  • 前五个 pngout 进程正常生成并开始工作
  • 10秒内2-5退出
  • 1 需要 45 秒
  • 尽管有四个线程空闲,但在此期间没有产生新的 pngout 进程
  • 完成 1 后,将生成另外五个进程。

代码:

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 将永远挂起。但是,显然使用 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 回答