freopen's blog

By freopen, 9 years ago, In Russian,
Мне захотелось наконец разобраться в способах ввода-вывода в C++, какой из них быстрее и удобнее. Поэтому я написал прогу, которая проверит скорость работы основных способов ввода/вывода в C++.
Итак, разберем все тесты по порядку:

Вывод программы

Test: (printf, 10000000 ints) 2.50c
Test: (cout, 10000000 ints) 3.02c
Test: (write, 10000000 ints, 104827485 chars) 2.88c + 0.25c
Test: (scanf, 10000000 ints) 2.61c
Test: (fwrite, 10000000 ints, 104827485 chars) 2.88c + 0.26c
Test: (cin, 10000000 ints) 8.32c
Test: (printf, 100000000 chars) 1.87c
Test: (scanf, 100000000 chars) 8.44c
Test: (cout, 100000000 chars) 6.98c
Test: (cin, 100000000 chars) 12.51c
Test: (putchar, 100000000 chars) 2.26c
Test: (getchar, 100000000 chars) 1.99c
Test: (read, 100000000 chars) 0.08c + 0.57c
Test: (fread, 100000000 chars) 0.08c + 0.59c

Разбор тестов

  1. printf вывел 107 целых чисел. Относительно быстро и удобно. Вполне можно использовать.
  2. Тоже самое сделал cout. Немного медленнее, но это когда как. Иногда cout работает довольно медленно.
  3. write, как функция ostream. Работает быстро. Очень быстро. Похоже, что в основе лежит fwrite. Первое время - преобразование чисел в строку. Второе - вывод. Примечательно, что вывод куда быстрее.
  4. scanf. Работает ровно также как и printf. Сносно и удобно в использовании.
  5. fwrite. Функция из C. Работает идентично write и сравнимо с ней по сложности использования. Ну может чуть чуть сложнее.
  6. Вот и первый fail. cin считывает числа медленно. Раза в 4 медленнее, чем все остальное. Если вам в программе требуется считать миллион чисел, готовьтесь потратить на это 0.8 секунд cin-а. А возможно и больше.
  7. Переходим к символам. printf выводит символы чуть быстрее, чем числа. Видимо, из-за отсутствия необходимости преобразовывать число.
  8. А вот это стало неожиданностью. scanf на редкость медленно читает символы. Файлик был размером около 100Мб, но все равно мог бы и побыстрее.
  9. cout выводит символы медленно. В 3 раза медленнее, чем printf.
  10. cin считывает символы совсем медленно. У меня уходило 1.2 секунды на каждые 10Мб. Есть и еще один сюрприз. Он выкидывает whitespace. Даже когда считывает один символ. Про это надо не забывать. Лечится так: cin >> noskipws;
  11. putchar. Предназначен для вывода одного символа. И это у него выходит прекрасно. 
  12. getchar. Предназначен для ввода одного символа. И также он это делает очень быстро.
  13. Наконец, блочный ввод-вывод. Опять указано два параметра. Первый - время считывания. Второй - проверка на правильность считывания. Второй нужен только для сравнения. Данные предсказуемо совпадают.
  14. См. выше

Вывод

  1. Для чисел лучше использовать cin(если время не очень критично), или printf(если критично).
  2. Для символов лучше использовать getchar и putchar.
  3. Что-то мне не верится в возможность считать 100Мб данных в оперативку за 0.08 секунд. Есть версия, что файл был кеширован в оперативке. Кто знает, как это проверить и как исправить - пишите в комменты.
  4. Надо доделать тесты для строк и дробного типа. Но это уже попозже.

Тем, кто хочет проверить это на своем компьютере

Пожалуйста. Вот программа: http://pastebin.com/DpmjHF7C. Учтите, что она заменит файл temp.txt на свой, а также ей надо 100Мб свободного места и 200Мб оперативки. И пришлите мне вывод программы в комменты или в личку. Под влиянием этих данных, я возможно, изменю разбор тестов. Большое спасибо всем, кто запустит прогу у себя и пришлет мне результаты, а также тем, кто укажет мне на неточности в программе или предложит другие тесты.
 
 
 
 
  • Vote: I like it  
  • +20
  • Vote: I do not like it  

8 years ago, # |
  Vote: I like it 0 Vote: I do not like it
спасибо за статью. помогла уложить в ограничения.
  • 8 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it
    Рад, что моя статья оказалась полезна. Зачем вы написали в английский интерфейс?
»
6 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Hi, I found that by adding ios_base::sync_with_stdio(false); cin.tie( static_cast<ostream*>(0) );

cin performance boosts drastically. However, it makes it work wrong when used along stdio.

  • »
    »
    6 years ago, # ^ |
    Rev. 3   Vote: I like it 0 Vote: I do not like it

    ios_base::sync_with_stdio(false) turns off synchornization between stdio and iostream, iostream standard stream objects may operate independently of standard C streams, and this leads to unexpectedly interleaved characters.

    Try to turn on and turn off synchronization between calling tests.

    • »
      »
      »
      6 years ago, # ^ |
      Rev. 2   Vote: I like it 0 Vote: I do not like it

      sync_with_stdio() can only be called before any input/output takes place.