Я оптимизирую файлы PNG, создав 5 процессов pngout.exe для работы с каталогом файлов PNG.Поскольку pngout является однопоточным, это приводит к значительному ускорению.Для оптимизации некоторых изображений требуется более 30 секунд, в то время как норма составляет <5 секунд.Проблема: </p>
- Файл 1 большой, 2-5 - маленький, всего 50 файлов, но подробности об остальном не имеют значения.
- Первые пять процессов pngout появляются нормально и начинают работать
- 2-5 выход в течение 10 секунд
- 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% по сравнению с однопоточным временем.
Что я делаю не так?
edit: Исправлена проблема с использованием действительно уродливого кода.Проблема в том, что для получения выходного значения процессов, которые я порождаю (чтобы знать, когда они завершены и если они преуспели), я считывал их стандартный вывод, поскольку вызов 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 из здесь , вероятно, более уместно.