Java избегает java.lang.OutOfMemoryError при чтении файла, но при одновременном использовании потоков - PullRequest
0 голосов
/ 01 июня 2019

Я пытаюсь прочитать очень большой файл с потоками, поэтому мне нужны параллельные потоки, а не итерации на строку ... Я пытаюсь сделать следующее:

String cont = new String(Files.readAllBytes(Paths.get(this.File_Path)),
            StandardCharsets.UTF_8);    
List<String> words = Arrays.asList(cont.split("\\PL+"));

yep = words.parallelStream()
            .filter(x -> x.contains(toMatch))
            .distinct()
            .collect(Collectors.toList());

Это работает для небольшого размера файла, но если я пытаюсь сделать то же самое с файлом, размер которого составляет несколько гигабайт, java выдает мне следующее исключение:

java.lang.OutOfMemoryError: Required array size too large

Есть способ избежать этого исключения, но одновременно использовать параллельный поток вместо итерации с BufferReader или Scanner?

Ответы [ 2 ]

1 голос
/ 02 июня 2019

Проблема Files.readAllBytes().Он загружает все содержимое файла в String, следовательно, в память.
Для чтения построчно вы хотите использовать Files.lines(), который возвращает Stream<String>, а затем преобразовать его в параллельный поток и выполнитьОперация transform для него:

List<String> words = 
    Files.lines(Paths.get(this.File_Path), charSetOfYourFileIfNotUTF8) // Stream<String>
         .parallel()
         .flatMap(s-> Arrays.stream(s.split("\\PL+"))) // Stream<String>
         .filter(x -> x.contains(toMatch))
         .distinct()
         .collect(Collectors.toList());

Что касается производительности, обратите внимание, что distinct() в параллельных конвейерах обходится дорого, если собирать данные поддерживают порядок.
Вам следует рассмотреть toSet(), чтобы улучшить дальнейшую производительность.

0 голосов
/ 02 июня 2019

Память кучи Java ограничена.Мы не можем прочитать целые данные файлов одновременно.Для определенного размера это просто невозможно (если только вы не увеличиваете кучу памяти, что не идеально по нескольким причинам).Что я бы порекомендовал, так это прочитать файл кусками, как несколько строк, возможно, фиксированный размер 1000 строк.Затем запустите операцию разбиения на массив и рассчитайте на этот кусок.
Вы можете распараллелить фрагменты с помощью многопоточности.

...