2015-06-12 3 views
1

Ниже приведен код, где я пытаюсь обрабатывать строки, считанные из файла в параллельном потоке и в обычном потоке. Удивительно, но параллельный поток не улучшает нормальный поток. Я что-то упустил?Параллельный поток создает только один поток и дает результат так же быстро, как обычный поток.

Files.walk(Paths.get(tweetFilePath + LocalDate.now())).forEach(
      filePath -> { 
       if (Files.isRegularFile(filePath) && !filePath.toString().endsWith(".DS_Store")) { 
        long startTime = System.currentTimeMillis(); 
        try { 

         Files.lines(filePath).parallel().forEach(line -> { 
           try { 
            System.out.println(line); 

           } catch (Exception e) { 
            System.out.println("Not able to crunch"+ e); 
           } 

         }); 
        } catch (Exception e) { 
         System.out.println("Bad line in file "); 
        }finally { 
         System.out.println("total time required:" + (System.currentTimeMillis() - startTime)); 

        } 
       } 
      }); 
+1

В этой ситуации узким местом является источник ввода-вывода - если у вас есть один физический жесткий диск, то вы можете параллелизировать, сколько хотите, оно не будет идти быстрее ... – assylias

+0

возможно вместо распараллеливания на линиях, которые вы могли бы Распараллеливать файлы – the8472

ответ

1

Похоже, в настоящее время, Files.lines читает файл линейно, поэтому параллельный вызов не может разделить поток источника в подпотоки для параллельной обработки.

См. Здесь details. Соответствующий раздел, приведенный ниже:

Что делать, если мой источник основан на IO?

В настоящее время JDK ввода-вывода на основе источников потока (например, BufferedReader.lines()) в основном приспособлены для последовательного применения, обрабатывающие элементы один за другим, как они прибывают. Существуют возможности для , поддерживающие высокоэффективную массовую обработку буферизованного ввода-вывода, но для этих в настоящее время требуется специальная разработка источников потока, разделителей, и/или коллекционеров. Некоторые распространенные формы могут поддерживаться в будущих выпусках JDK .

+0

Это кажется правильным. Я собрал все строки из файла в список, а затем параллельно передал его. Сейчас это значительно быстрее. Благодаря! – Kaunteya

1

Первая проблема заключается в том, что Files.lines плохо разбирается в особенностях файлов размером менее 1024 строк. Проверьте this вопрос для деталей. Если вы заранее знаете, что ваш файл достаточно мал, чтобы поместиться в памяти, было бы лучше, чтобы прочитать его последовательно к List первым:

Files.readAllLines(filePath, StandardCharsets.UTF_8).parallelStream()... 

У меня есть некоторые идеи о том, как improve this, но это по-прежнему не идеальна решение. Дело в том, что распараллеливание Stream API довольно неэффективно, если вы даже не можете оценить количество элементов во входном потоке.

Вторая проблема заключается в вашей операции forEach. Здесь вы просто используете System.out, так что все потоки попытаются написать то же самое PrintStream, борясь за один и тот же ресурс, поэтому большую часть времени будет потрачено на ожидание релиза блокировки. Внутри он использует BufferedWriter, где все записи синхронизированы. Вы можете воспользоваться распараллеливанием, если вы не используете общие ресурсы в параллельных операциях.

Кстати Files.lines создает поток над BufferedReader. Лучше управлять им с помощью инструкции try-with-resources. В противном случае файлы будут закрыты только в том случае, если базовые объекты FileInputStream собираются с мусором, поэтому вы можете спорадически иметь такие ошибки, как «слишком много открытых файлов».

Смежные вопросы