Если вы обнаружили, что наибольшее количество времени в выполнении занимает запись выходных данных, это уже является хорошим показателем того, где наибольшее увеличение скорости. У вас был правильный рефлекс измерения, прежде чем пытаться оптимизировать.
Первый шаг - убедиться, что FileWriter
(или FileOutputStream
, в зависимости от того, что вы используете) заключен в BufferedWriter
или BufferedOutputStream
с достаточно большим буфером. Это позволяет Java помещать вывод в буфер и сбрасывать его в файл только после заполнения. Объем вывода не изменяется, но он распределяется по меньшим количествам вызовов ввода / вывода.
Если это не сработает, изучите руководства по использованию классов в пакете java.nio
. Этот API, представленный в Java 1.4, и расширение Java NIO.2, обеспечивающее возможности файловой системы, были добавлены в Java SE 7. Они обеспечивают неблокирующий ввод / вывод. Идея неблокирующего ввода-вывода состоит в том, что потоки, как правило, проводят много времени в традиционных операциях ввода-вывода, ожидая, пока базовая ОС и аппаратное обеспечение завершат чтение и запись, не выполняя при этом никакой полезной работы. С неблокирующим вводом / выводом вы помещаете вывод в буфер и записываете его асинхронно, что означает, что вызов write возвращается немедленно и может продолжить другую полезную работу, пока системные вызовы завершают передачу. Это отличается от обычного BufferedWriter или BufferedOutputStream, которые предоставляют буфер в памяти, но блокируют его запись, когда буфер очищается.
Использование неблокирующего ввода-вывода позволяет вашему приложению извлекать больше данных из ввода и / или процесса, которые в процессе записи выводятся для лучшей параллельной обработки. Однако, если на выходной стороне имеется большое узкое место, поскольку чтение и обработка всегда «догоняют» запись, переполняя буфер выходного канала, вывод все равно будет ограничивающим фактором. В конце концов, все выходные данные должны быть записаны в файл.
Метод выполнения параллельного вывода при одновременной проверке того, что вывод остается в предсказуемом порядке, заключается в использовании отображенного в память файла. Для этого вы бы использовали java.io.RandomAccessFile
, который также можно комбинировать с java.nio для асинхронной записи. Затем вы можете записывать в разные части файла параллельно. Недостатком здесь является то, что для каждой части вашего вывода вы должны быть уверены, что он имеет определенную длину. За исключением некоторых очень специфических вариантов использования (таких как текст фиксированной длины или некоторый двоичный формат), обычно это не так.
Наконец, возможна параллельная обработка ввода и последующая проверка того, что он по-прежнему записан в правильном порядке, независимо от того, с какими частями ввода были обработаны в первую очередь. Вам просто нужно поставить в очередь выходные данные с некоторыми метаданными (например, обернуть их в некоторый вспомогательный класс), идентифицирующими порядок, и сделать так, чтобы выходные данные ничего не записывали не в порядке. Некоторые библиотеки могут предлагать что-то полезное, но может быть достаточно очереди с приоритетами, в которых объекты обертывают вывод и имеют порядковый номер. Это шаблон, известный как resequencer в шаблонах интеграции .