Мне захотелось наконец разобраться в способах ввода-вывода в C++, какой из них быстрее и удобнее. Поэтому я написал прогу, которая проверит скорость работы основных способов ввода/вывода в C++. Вывод программы
Итак, разберем все тесты по порядку:
Вывод программы
Test: (printf, 10000000 ints) 2.50cTest: (cout, 10000000 ints) 3.02cTest: (write, 10000000 ints, 104827485 chars) 2.88c + 0.25cTest: (scanf, 10000000 ints) 2.61cTest: (fwrite, 10000000 ints, 104827485 chars) 2.88c + 0.26cTest: (cin, 10000000 ints) 8.32cTest: (printf, 100000000 chars) 1.87cTest: (scanf, 100000000 chars) 8.44cTest: (cout, 100000000 chars) 6.98cTest: (cin, 100000000 chars) 12.51cTest: (putchar, 100000000 chars) 2.26cTest: (getchar, 100000000 chars) 1.99cTest: (read, 100000000 chars) 0.08c + 0.57cTest: (fread, 100000000 chars) 0.08c + 0.59c
Разбор тестов
- printf вывел 107 целых чисел. Относительно быстро и удобно. Вполне можно использовать.
- Тоже самое сделал cout. Немного медленнее, но это когда как. Иногда cout работает довольно медленно.
- write, как функция ostream. Работает быстро. Очень быстро. Похоже, что в основе лежит fwrite. Первое время - преобразование чисел в строку. Второе - вывод. Примечательно, что вывод куда быстрее.
- scanf. Работает ровно также как и printf. Сносно и удобно в использовании.
- fwrite. Функция из C. Работает идентично write и сравнимо с ней по сложности использования. Ну может чуть чуть сложнее.
- Вот и первый fail. cin считывает числа медленно. Раза в 4 медленнее, чем все остальное. Если вам в программе требуется считать миллион чисел, готовьтесь потратить на это 0.8 секунд cin-а. А возможно и больше.
- Переходим к символам. printf выводит символы чуть быстрее, чем числа. Видимо, из-за отсутствия необходимости преобразовывать число.
- А вот это стало неожиданностью. scanf на редкость медленно читает символы. Файлик был размером около 100Мб, но все равно мог бы и побыстрее.
- cout выводит символы медленно. В 3 раза медленнее, чем printf.
- cin считывает символы совсем медленно. У меня уходило 1.2 секунды на каждые 10Мб. Есть и еще один сюрприз. Он выкидывает whitespace. Даже когда считывает один символ. Про это надо не забывать. Лечится так: cin >> noskipws;
- putchar. Предназначен для вывода одного символа. И это у него выходит прекрасно.
- getchar. Предназначен для ввода одного символа. И также он это делает очень быстро.
- Наконец, блочный ввод-вывод. Опять указано два параметра. Первый - время считывания. Второй - проверка на правильность считывания. Второй нужен только для сравнения. Данные предсказуемо совпадают.
- См. выше
Вывод
- Для чисел лучше использовать cin(если время не очень критично), или printf(если критично).
- Для символов лучше использовать getchar и putchar.
- Что-то мне не верится в возможность считать 100Мб данных в оперативку за 0.08 секунд. Есть версия, что файл был кеширован в оперативке. Кто знает, как это проверить и как исправить - пишите в комменты.
- Надо доделать тесты для строк и дробного типа. Но это уже попозже.
Тем, кто хочет проверить это на своем компьютере
Пожалуйста. Вот программа: http://pastebin.com/DpmjHF7C. Учтите, что она заменит файл temp.txt на свой, а также ей надо 100Мб свободного места и 200Мб оперативки. И пришлите мне вывод программы в комменты или в личку. Под влиянием этих данных, я возможно, изменю разбор тестов. Большое спасибо всем, кто запустит прогу у себя и пришлет мне результаты, а также тем, кто укажет мне на неточности в программе или предложит другие тесты.
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.
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.
sync_with_stdio()
can only be called before any input/output takes place.Checked.. Yes, you are right