Эффективный файловый ввод / вывод и преобразование строк в числа с плавающей запятой - PullRequest
2 голосов
/ 14 января 2010

У меня есть несколько гигантских (несколько гигабайт) текстовых файлов ASCII, которые мне нужно читать построчно, преобразовывать определенные столбцы в числа с плавающей запятой и выполнять несколько простых операций с этими числами. Это довольно простой материал, за исключением того, что я думаю, что должен быть способ ускорить процесс. Программа никогда не использует эквивалент 100% ядра ЦП, потому что тратит так много времени на ожидание ввода / вывода. В то же время он тратит достаточно времени на вычисления, а не на ввод-вывод, так как он выполняет только ~ 8-10 МБ / с для ввода-вывода на сыром диске. Я видел, как мой жесткий диск работает намного лучше.

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

Edit: я использую язык программирования D, стандартную библиотеку версии 2, в основном функции более высокого уровня, для большинства этих вещей прямо сейчас. Размер буфера, используемого std.stdio.File, составляет 16 КБ.

Ответы [ 4 ]

1 голос
/ 14 января 2010

Если вы не используете 100% ЦП, значит, вы связаны с вводом / выводом и не увидите большого / какого-либо улучшения благодаря многопоточности - у вас будет несколько потоков, ожидающих ввода / вывода. На самом деле, если они обращаются к разным частям файла, вы можете ввести поиск дисков и сделать все намного хуже.

Сначала рассмотрим более простые вещи: можете ли вы увеличить объем буферной памяти, доступной для ввода / вывода? (например, в C ++ стандартные буферы ввода / вывода для объектов FILE крошечные (например, 4 КБ), установка большего буфера (например, 64 КБ) может существенно повлиять на пропускную способность).

Можете ли вы использовать больший размер буфера в ваших запросах ввода / вывода: например, Считайте 64 КБ необработанных данных в большой буфер, а затем обработайте их самостоятельно, вместо того, чтобы читать по одной строке или одному байту за раз.

Вы выводите какие-либо данные? Кэшируя это в ОЗУ вместо того, чтобы записывать его немедленно на диск, вы можете ограничить свой ввод-вывод простым чтением входного файла и помочь вещам идти намного быстрее.

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

0 голосов
/ 14 января 2010

Обычно ОС пытается читать вперед, и вы должны приблизиться к предельной скорости жесткого диска, если вы не привязаны к процессору.

Причиной может быть:

  • Большой файл фрагментирован (вы можете дефрагментировать том и проверить, все ли работает лучше)
  • ОС не использует чтение вперед (как решение: в Windows вы можете использовать CreateFile с флагом, что вы будете сканировать файл)
  • Вы не используете эффективную буферизацию (например, если вы читаете из дескриптора файла ОС только несколько байт за раз, все будет медленно. (Вы можете попытаться прочитать большие куски сразу)

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

0 голосов
/ 14 января 2010

Прежде всего, я бы взял у вас программу и получил ее отрывки. Это точно скажет, сколько времени тратится на ввод-вывод и сколько на процессор.

Тогда, если ввод / вывод является доминирующим, я бы удостоверился, что я читаю буферы как можно большего размера, чтобы минимизировать движения головки диска.

Затем, если я вижу, что ввод-вывод ожидает ЦП, а затем ЦП ожидает ввода-вывода, я бы попытался выполнить асинхронный ввод-вывод, чтобы один буфер мог загружаться, пока ЦП работает на другом. , (Или вы можете сделать это с потоком чтения, читая в альтернативные буферы.)

Если ввод-вывод не является доминирующим, а ЦП - доминирующим, то я бы посмотрел, что мне дают стековые снимки об активности ЦП. Если чрезмерный процент времени тратится на деформатирование чисел с плавающей запятой, и если числа имеют довольно простой формат, я бы сам решил их проанализировать, потому что могу воспользоваться преимуществами более простого формата.

Это помогает?

0 голосов
/ 14 января 2010

Если у вас достаточно ОЗУ, вы можете прочитать весь файл в строку, разложить его на разделители строк и обработать токены так, как вы хотите.

В Java вы должны использовать объект StringBuilder для чтения содержимого файла в него. Вы также хотели бы запустить jvm с достаточным ограничением памяти (в данном примере 2 ГБ), используя что-то вроде:

java -Xmx 2048 -Xms 2048 -jar MyMemoryHungryApp.jar

Если вы не хотите читать весь файл в строку, вы можете итеративно читать его в пакетах и ​​обрабатывать пакеты.

Фактически, в зависимости от деталей вашего формата файла, вы, вероятно, могли бы использовать CSVReader с открытым исходным кодом Java-пакетом ( страница проекта ), чтобы прочитать ваш файл в память, используя метод readAll (), и вы в итоге получится List<String[]> и вы сможете поехать в город на нем:).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...