Мне нужно прочитать изображения из папки и сгенерировать для них контрольную сумму. Есть около 330760 изображений. Ниже приведен код:
package com.test;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.apache.commons.codec.digest.DigestUtils;
public class FileTest2 {
private void readFiles() throws IOException {
try (Stream<Path> filePathStream = Files
.walk(Paths.get("d:\\codebase\\images"))) {
filePathStream.parallel().forEach(filePath -> {
String checksumSHA256 = "";
try {
checksumSHA256 = DigestUtils.sha384Hex(new FileInputStream(filePath.toString()));
} catch (IOException e) {
e.printStackTrace();
}
if (Files.isRegularFile(filePath)) {
System.out.println(checksumSHA256);
System.out.println(filePath);
System.out.println("\n");
}
});
}
}
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
FileTest2 fileTest = new FileTest2();
fileTest.readFiles();
long endTime = System.currentTimeMillis();
System.out.println("Total Time took: " + (endTime - startTime) / 1000);
}
}
На это ушло около 36 минут.
Конфигурация системы:
Количество ядер: 8
Память: 32 ГБ (свободно 15-17 ГБ). Остальная часть памяти используется другим сервером.
36 минут - это слишком много. Есть ли способ повысить производительность?
Вы запустили пул потоков, который все еще активен, хотя ему нечего делать. Он просто сидит без дела в ожидании работы. Зачем вы создали пул потоков? Ваш код ничего не делает многопоточным. В любом случае, выключите исполнителя.
Как вы думаете, почему программа должна «забирать всю память»? Ваша программа ничего не делает. --- Почему вы задали вопрос о медленном коде, а затем не спросили о медленном коде или даже не показали, что он медленный? Пожалуйста редактировать вопрос и уберите его !!!
да. Я не успел закрыть исполнителя.
Что значит мой код ничего не делает? Он читает все файлы / изображения из файловой системы и выводит имя на консоль.
Зачем вообще беспокоиться о пуле потоков? Вы пробовали filePathStream.parallel().forEach? Кроме того, это неправильный тест.
@PuneetJain Код не делает ничего, что потребляет много памяти. Вы печатаете все имена файлов по одному, поэтому в памяти одновременно находится только одно имя. Вы не читаете файлы (контент), а только их имена, так почему вы думаете, что код будет использовать много памяти?
Вы пробовали использовать VisualVM или любой другой профилировщик Java для проверки потребления памяти вместо диспетчера задач Windows? Также вы используете ключ -Xms при запуске приложения Java?
@ Иван - Еще нет. Но планирую использовать.
@ JacobG. Не пробовал параллельно. Можете попробовать
Обновил мой код. Генерация контрольной суммы для всех изображений.
@ JacobG. Я только что закончил пробовать с параллельным сервером, и это заняло: 2086 секунд.
Почему вы тестируете Files.isRegularFile(filePath)после, вы рассчитали для него контрольную сумму? Не поздно ли поставить под сомнение эту собственность? Кроме того, не рекомендуется выполнять три отдельных оператора печати с потоком параллельный, когда каждый другой поток мог бы выполнять свои собственные операторы печати между ними. Кроме того, почему вы идете по старому обходному пути ввода-вывода, то есть new FileInputStream(filePath.toString()), вместо использования Files.newInputStream(filePath)?




Как указывали другие, вы не увольняете исполнителя. Чтобы увидеть фактическое время, запустите следующее
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
FileTest fileTest = new FileTest();
fileTest.readFiles();
long endTime = System.currentTimeMillis();
System.out.println("Total Time took: "+ (endTime-startTime)/1000);
}
Примечание: по крайней мере, из того фрагмента кода, который вы опубликовали, нет причин использовать ExecutorService
Только что обновил свой код. Генерация контрольной суммы для всех изображений.
Пожалуйста, запустите предложенный мной код и сообщите значение «Общее время:»
Я только что закончил параллель, и это заняло: 2086 секунд. filePathStream.parallel (). forEach (filePath -> {} Еще пробовать без параллелизма, но я уверен, что это было бы ужасно,
Прокомментируйте, пожалуйста, распечатанные утверждения и укажите значение «Общее время:»
Кроме того, с реализацией sha вы измеряете не только время, необходимое для обхода файловой системы, но также время, необходимое для чтения каждого файла.
Хорошо. Прокомментирую и попробую. В настоящее время пытаюсь без parallel (). Для SHA - по сути, мой код будет генерировать sha для всех изображений и сохранять их в базе данных. Мне нужно запускать этот код один раз в день. Так что я стараюсь добиться максимальной производительности. Я считаю, что это замедлится еще больше, если я сохраню SHA в базе данных.
Заняло 9988 секунд без parallel (). Пробую без println сейчас.
2137 секунд без println и с parallel ().
Итак, около 7 мсек. на файл. Вы можете улучшить ситуацию, используя BufferedInputStream
Похоже, что на самом деле это не заняло так много времени, поскольку я могу видеть все записи / пути к именам файлов в текстовом файле. Однако код все еще выполняется. Я пропустил закрытие какого-либо ресурса здесь?