Подтвердить что ты не робот

Разница в производительности между файлами стилей C и С++ IO

Я всегда слышал, что операции ввода-вывода файлов на С++ намного медленнее, чем C-стиль ввода-вывода. Но я не нашел практических ссылок относительно того, насколько медленны они на самом деле, поэтому я решил проверить его на своей машине (Ubuntu 12.04, GCC 4.6.3, формат раздела ext4).

Сначала я написал файл размером ~ 900 МБ на диске.

С++ (ofstream): 163s

ofstream file("test.txt");

for(register int i = 0; i < 100000000; i++) 
    file << i << endl;

C (fprintf): 12s

FILE *fp = fopen("test.txt", "w");

for(register int i = 0; i < 100000000; i++) 
    fprintf(fp, "%d\n", i);

Я ожидал такой вывод, он показывает, что запись в файл намного медленнее в С++ C. Затем я читаю тот же файл, используя C и С++ I/O. Что заставило меня воскликнуть, что при чтении из файла практически нет разницы в производительности.

С++ (ifstream): 12s

int n;
ifstream file("test.txt");

for(register int i = 0; i < 100000000; i++) 
    file >> n;

C (fscanf): 12s

FILE *fp = fopen("test.txt", "r");

for(register int i = 0; i < 100000000; i++) 
    fscanf(fp, "%d", &n);

Итак, почему так долго приходится выполнять запись с использованием потока? Или, почему чтение с использованием потока настолько быстро по сравнению с написанием?

Вывод: Преступник - это std::endl, как указывали ответы и комментарии. Изменение линии file << i << endl; в file << i << '\n'; сократил время работы до 16 с от 163 с.

4b9b3361

Ответ 1

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

Используйте \n, если вы имеете в виду так:

file << i << '\n';

Кроме того, необходимо скомпилировать ваш код в режиме выпуска (например, включить оптимизацию).

Ответ 2

Нет, ввод/вывод С++ не существенно медленнее, чем Cs. Если что-либо, современная реализация должна быть немного быстрее на форматированном вводе/выводе, так как не нужно разбирать строку формата, а форматирование вместо этого определяется во время компиляции через цепочку операторов потока.

Вот несколько предостережений, которые следует учитывать в тесте:

  • Скомпилируйте с полной оптимизацией (-O3), чтобы получить справедливое сравнение.
  • Правильный тест должен оценивать предубеждения - на практике это означает, что вам нужно повторять свои тесты и чередовать их. На данный момент ваш код не устойчив к нарушениям фоновых процессов. Вы также должны сообщить сводную статистику повторных прогонов, чтобы поймать выбросы, искажающие оценки.
  • Отключить синхронизацию потока С++ с потоками C (std::ios_base::sync_with_stdio(false);)
  • Используйте '\n' вместо (промывки) std::endl
  • Не используйте объявления register - это просто не имеет значения, и современные компиляторы, вероятно, все равно игнорируют его.

Ответ 3

При работе с большими файлами с fstream убедитесь, что установить буфер потокa > 0.

В отличие от этого, отключение буферизации потоков значительно снижает производительность. По меньшей мере, реализация MSVC 2015 копирует 1 char за раз до filebuf, когда буфер не был установлен (см. streambuf::xsputn), что может сделать ваше приложение привязанным к процессору, что приведет к снижению ставок ввода-вывода.

const size_t bufsize = 256*1024;
char buf[bufsize];
mystream.rdbuf()->pubsetbuf(buf, bufsize);

Здесь вы можете найти полное примерное приложение .