Одна идея состоит в том, чтобы использовать алгоритм fork / join и группировать элементы (файлы) в пакеты для индивидуальной обработки.
Мое предложение следующее:
- Во-первых, отфильтруйте все файлы, которые не существуют - они занимают ресурсы без необходимости.
Следующий псевдокод демонстрирует алгоритм, который может вам помочь:
public static class CustomRecursiveTask extends RecursiveTask<Integer {
private final Analyzer[] analyzers;
private final int threshold;
private final File[] files;
private final int start;
private final int end;
public CustomRecursiveTask(Analyzer[] analyzers,
final int threshold,
File[] files,
int start,
int end) {
this.analyzers = analyzers;
this.threshold = threshold;
this.files = files;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
final int filesProcessed = end - start;
if (filesProcessed < threshold) {
return processSequentially();
} else {
final int middle = (start + end) / 2;
final int analyzersCount = analyzers.length;
final ForkJoinTask<Integer> left =
new CustomRecursiveTask(analyzers, threshold, files, start, middle);
final ForkJoinTask<Integer> right =
new CustomRecursiveTask(analyzers, threshold, files, middle + 1, end);
left.fork();
right.fork();
return left.join() + right.join();
}
}
private Integer processSequentially() {
for (int i = start; i < end; i++) {
File file = files[i];
for(Analyzer analyzer : analyzers) { analyzer.analyze(file) };
}
return 1;
}
}
И использование выглядит следующим образом:
public static void main(String[] args) {
final Analyzer[] analyzers = new Analyzer[]{};
final File[] files = new File[] {};
final int threshold = files.length / 5;
ForkJoinPool.commonPool().execute(
new CustomRecursiveTask(
analyzers,
threshold,
files,
0,
files.length
)
);
}
Обратите внимание, что в зависимости от ограничений вы можете манипулировать аргументами конструктора задачи, чтобы алгоритм подстраивался под количество файлов.
Вы можете указать различные threshold
s, скажем, в зависимости от количества файлов.
final int threshold;
if(files.length > 100_000) {
threshold = files.length / 4;
} else {
threshold = files.length / 8;
}
Вы также можете указать количество рабочих потоков в ForkJoinPool
в зависимости от введенного количества.
Измерьте, отрегулируйте, измените, в конечном итоге вы решите проблему.
Надеюсь, это поможет.
UPDATE:
Если анализ результатов не представляет интереса, вы можете заменить RecursiveTask
на RecursiveAction
. Псевдокод добавляет промежуточный автобокс между ними.