Быстрый кроссплатформенный алгоритм для чтения / записи файла в C ++ - PullRequest
5 голосов
/ 26 января 2010

Я хочу задать, казалось бы, простой вопрос, на который я не могу найти ответа нигде. Существует ли FAST современный алгоритм для ввода и / или вывода файлов, который можно скомпилировать со всеми стандартными компиляторами C ++ и который работает для всех операционных систем без необходимости использования внешних библиотек?

  1. Я обнаружил, что самый быстрый способ - использовать файлы с отображением в памяти, но этого не произойдет, потому что мы хотим, чтобы один и тот же кусок кода работал на всех платформах
  2. мы не можем использовать API-интерфейсы, такие как Win32 API, потому что это будет зависеть от платформы
  3. я не хочу использовать c, я хочу, чтобы алгоритм был просто чистым кодом c ++ с stl, если это возможно, а не каким-то уродливым c с смешанным asm hack / trick
  4. каркасы или внешние библиотеки, которые не входят в стандартную версию c ++, не должны использоваться как wxWidgets, Qt, MFC и т. Д.
  5. Большим акцентом всего этого вопроса является то, что алгоритм максимально возможен FAST , что-то вроде скорости работы с файлами, отображенными в память, даже быстрее, было бы здорово, но я знаю, что не возможно

Вы когда-нибудь видели что-то такое безумное, исследованное кем-то еще, кроме меня? Возможен ли такой алгоритм?

Спасибо за любые рекомендации

Ответы [ 7 ]

9 голосов
/ 26 января 2010

Это не имеет ничего общего с "алгоритмом".

Когда дело доходит до записи данных в файл, вы попадаете в зависимость от операционной системы - отображаемые в память файлы «быстрые», потому что вы просто записываете в память, а ОС синхронизирует их с собственное время Если ОС не поддерживает это, вам не повезло в этом отношении - если вы не хотите реализовать свой собственный слой отображения памяти.

Кстати, POSIX имеет mmap, поэтому, если вы ограничиваете себя системами, совместимыми с POSIX, у вас все в порядке.

9 голосов
/ 26 января 2010

Со следующими ограничениями:

может быть скомпилирован со всеми стандартными компиляторами C ++ и работает для всех операционных систем без необходимости использования внешних библиотек?

You 'Мы в значительной степени ограничились стандартными функциями ввода-вывода файла библиотеки.Может быть, POSIX работает (в зависимости от того, какое подмножество «всех стандартных совместимых компиляторов C ++» вы рассматриваете).

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

4 голосов
/ 26 января 2010

Чтобы еще раз взглянуть на "милость ОС", большая часть накладных расходов при копировании файлов лежит на операционной системе.Для фрагментированного файла потребуется больше времени для чтения, чем для дефрагментированного файла.Не существует универсальных или стандартных функций C ++ для обнаружения фрагментированных файлов.

Самый быстрый метод в C ++:

std::ifstream in_file;
std::ofstream out_file;

out_file << in_file.rdbuf();

Более подробную информацию можно найти, выполнив поиск в Интернете по ключевым словам " copy file rdbuf ".Вышеуказанный фрагмент оставляет копирование до ОС, но переносимо на все платформы.Читая в потоках ввода / вывода C ++, вы можете установить размер буфера чтения или использовать свой собственный буфер.

Более быстрое копирование файлов требует определенных функций платформы, таких как передача DMA.Использование потоков и множественной буферизации может ускорить это;но C ++ не поддерживает потоки (есть стандарт defacto, POSIX, который поддерживает потоки).Один поток будет читать в буферы, в то время как другой поток пишет из буферов.

2 голосов
/ 26 января 2010

Некоторые баллы:

  • Это не имеет ничего общего с алгоритмами.
  • Желание нацелиться на ВСЕ операционные системы - не очень продуктивная цель (и это невозможно
  • ваш код не работает на конкретной платформе, пока вы не протестировали его). Вместо этого я бы сосредоточился на некотором наборе операционных систем, которые возможны - скажем, POSIX + Win32.
  • В этом случае вы можете сделать отображение памяти, например, реализовав mmap () для Windows (поверх MapViewOfFile () и т. Д. - исходный код git имеет реализацию mmap для Windows, если вам нужно немного вдохновения) *
  • Если вы не можете использовать отображение памяти, я бы порекомендовал использовать обычный файл C API, а не потоки файлов C ++, если производительность имеет большое значение. Несмотря на то, что потоки C ++ имеют потенциал для более высокой производительности для некоторых операций, на практике это немного медленнее.
  • Но, чтобы добиться хорошей производительности, она часто может быть «достаточно хорошей», чтобы быть уверенным, что вы обрабатываете свои данные в здравом уме. Читайте данные последовательно, не перечитывайте и т. Д. Perfect - враг добра;)
1 голос
/ 26 января 2010

Быстрый IO обычно сводится к двум вещам:

  1. Минимизация копирования данных
  2. Минимизация переключения контекста ядра / пользователя

Большинство попыток ввода-выводаобратиться к одному или другому.Самый быстрый кроссплатформенный код для IO, о котором я знаю, - это система Perl IO.Я бы посоветовал взглянуть на источник .Хакеры Perl потратили десятилетия, чтобы как можно быстрее сделать свой ввод-вывод на максимально возможном количестве платформ.

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

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

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

В любом случае, если вы попробуете эти идеи, пожалуйста, сообщите нам, если вы заметите разницу. Фактические результаты ваших тестов производительности будут интересны.

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

Другие постеры верны в том, что производительность всегда идет вразрез с универсальностью (кроссплатформенность).

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

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

...