Использование scanf () в программах на C++ быстрее, чем использование cin?
Я не знаю, правда ли это, но когда я читал FAQ на одном из проблемных сайтов, я нашел что-то, что привлекло мое внимание:
Проверьте свои методы ввода / вывода. В C++ использование cin и cout слишком медленно. Используйте их, и вы гарантированно не сможете решить любую проблему с приличным количеством ввода или вывода. Вместо использования printf и scanf.
может кто-нибудь прояснить это? Действительно использует scanf () в C++ программы быстрее, чем с помощью cin > > что-то ? Если да, то это хорошая практика, чтобы использовать его в программах на C++? Я думал, что это специфический C, хотя я просто изучаю C++...
13 ответов:
вот быстрый тест простого случая: программа для чтения списка чисел из стандартного ввода и XOR всех чисел.
версия iostream:
#include <iostream> int main(int argc, char **argv) { int parity = 0; int x; while (std::cin >> x) parity ^= x; std::cout << parity << std::endl; return 0; }версия scanf:
#include <stdio.h> int main(int argc, char **argv) { int parity = 0; int x; while (1 == scanf("%d", &x)) parity ^= x; printf("%d\n", parity); return 0; }результаты
используя третью программу, я сгенерировал текстовый файл, содержащий 33 280 276 случайных чисел. Время выполнения:
iostream version: 24.3 seconds scanf version: 6.4 secondsизменение настроек оптимизации компилятора не похоже, чтобы результаты сильно изменились.
таким образом: действительно есть разница в скорости.
EDIT: пользователь clyfish указывает ниже что разница в скорости в значительной степени обусловлена функциями ввода-вывода iostream, поддерживающими синхронизацию с функциями ввода-вывода C. Мы можем отключить это с помощью вызова
std::ios::sync_with_stdio(false);:#include <iostream> int main(int argc, char **argv) { int parity = 0; int x; std::ios::sync_with_stdio(false); while (std::cin >> x) parity ^= x; std::cout << parity << std::endl; return 0; }новые результаты:
iostream version: 21.9 seconds scanf version: 6.8 seconds iostream with sync_with_stdio(false): 5.5 secondsC++ iostream выигрывает! Получается, что эта внутренняя синхронизация / промывки является то, что обычно замедляет библиотеки ввода/вывода. Если мы не смешивая с cstdio и библиотеки iostream, мы можем отключить его, а затем библиотеки iostream, является самым быстрым.
http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma
производительность
cin/coutможет быть медленным, потому что они должны держать себя в синхронизации с базовой библиотеки языка Си. Это важно, если будут использоваться как C IO, так и C++ IO.однако, если вы собираетесь использовать только c++ IO, то просто используйте нижеприведенную строку перед любыми операциями ввода-вывода.
std::ios::sync_with_stdio(false);для получения дополнительной информации об этом, посмотрите на соответствующие libstdc++ docs.
вероятно, scanf несколько быстрее, чем использование потоков. Хотя потоки обеспечивают большую безопасность типов и не должны анализировать строки формата во время выполнения, обычно это имеет преимущество, не требуя чрезмерного выделения памяти (это зависит от вашего компилятора и среды выполнения). Тем не менее, если производительность не является вашей единственной конечной целью, и вы находитесь на критическом пути, тогда вы действительно должны отдавать предпочтение более безопасным (медленным) методам.
здесь есть очень вкусная статья, написанная Herb Саттер"строка форматирования из фермерской усадьбы " кто вдается в много деталей производительности струнных форматтеров, таких как
sscanfиlexical_castи какие вещи заставляли их бежать медленно или быстро. Это похоже на то, что, вероятно, повлияет на производительность между C style IO и C++ style. Главным отличием от форматеров, как правило, является безопасность типа и количество выделений памяти.
Я только что провел вечер, работая над проблемой на UVa Online (Factovisors, очень интересная проблема, проверьте ее):
Я получал TLE (превышение срока) на моих представлениях. На этих сайтах онлайн-судей для решения проблем у вас есть 2-3-секундный лимит времени для обработки потенциально тысяч тестовых случаев, используемых для оценки ваше решение. Для таких вычислительно интенсивных задач, как эта, каждая микросекунда имеет значение.
Я использовал предложенный алгоритм (читайте об этом в дискуссионных форумах для сайта), но все еще получал TLEs.
Я изменил только "cin > > n >> m "на "scanf ("%d %d", &n, &m) "и несколько крошечных" couts "на" printfs", и мой TLE превратился в"принято"!
Так что, да, это может иметь большое значение, особенно когда сроки коротки.
Вау, говорить о преждевременной оптимизации. Если бы не нелепая оптимизация. I / O будет узким местом вашей программы задолго до
cin >> xmaxes из вашего процессора quadcore.хорошо, ехидство в сторону: Нет, это не хорошая практика, чтобы поменять
<iostream>на<cstdio>. В C++ используйте библиотеки C++. Не используйтеscanf, не называйmalloc, не проходят идти, не собирают $200.
Если вы заботитесь о производительности и форматировании строк, посмотрите на Фастформат Мэтью Уилсона библиотека.
edit -- ссылка на публикацию accu в этой библиотеке:http://accu.org/index.php/journals/1539
да iostream медленнее, чем cstdio.
Да, вы, вероятно, не должны использовать cstdio, если вы разрабатываете в C++.
Сказав это, есть еще более быстрые способы получить ввод-вывод, чем scanf, если вы не заботитесь о форматировании, безопасности типа, бла-бла-бла...например, это пользовательская процедура для получения номера из STDIN:
inline int get_number() { int c; int n = 0; while ((c = getchar_unlocked()) >= '0' && c <= '9') { // n = 10 * n + (c - '0'); n = (n << 3) + ( n << 1 ) + c - '0'; } return n; }
есть реализации stdio (libio), который реализует FILE* как C++ streambuf и fprintf как синтаксический анализатор формата времени выполнения. IOstreams не нуждаются в анализе формата времени выполнения, это все делается во время компиляции. Таким образом, с общими бэкэндами разумно ожидать, что iostreams будет быстрее во время выполнения.
проблема в том, что
cinимеет много накладных расходов, потому что это дает вам уровень абстракции вышеscanf()звонки. Вы не должны использоватьscanf()overcinЕсли вы пишете программы на C++, потому что хочу!--0--> для. Если вам нужна производительность, вы, вероятно, не будете писать ввод-вывод в C++ в любом случае.
заявления
cinиcoutВ общем использовании, кажется, медленнее, чемscanfиprintfв C++, но на самом деле они быстрее!дело в том, что в C++, когда вы используете
cinиcoutпроцесс синхронизации происходит по умолчанию, которая гарантирует, что если вы используете обаscanfиcinв вашей программе, то они оба работают в синхронизации друг с другом. Этот процесс синхронизации требует времени. Отсюдаcinиcoutпохоже, что замедлившийся.однако, если процесс синхронизации не выполняется,
cinбыстрееscanf., чтобы пропустить процесс синхронизации, включите следующий фрагмент кода в вашу программу в начале
main():std::ios::sync_with_stdio(false);посетить этот сайт для получения дополнительной информации.
#include <stdio.h> #include <unistd.h> #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) static int scanuint(unsigned int* x) { char c; *x = 0; do { c = getchar_unlocked(); if (unlikely(c==EOF)) return 1; } while(c<'0' || c>'9'); do { //*x = (*x<<3)+(*x<<1) + c - '0'; *x = 10 * (*x) + c - '0'; c = getchar_unlocked(); if (unlikely(c==EOF)) return 1; } while ((c>='0' && c<='9')); return 0; } int main(int argc, char **argv) { int parity = 0; unsigned int x; while (1 != (scanuint(&x))) { parity ^= x; } parity ^=x; printf("%d\n", parity); return 0; }в конце файла есть ошибка, но этот код C значительно быстрее, чем более быстрая версия C++.
paradox@scorpion 3845568-78602a3f95902f3f3ac63b6beecaa9719e28a6d6 ▶ make test time ./xor-c < rand.txt 360589110 real 0m11,336s user 0m11,157s sys 0m0,179s time ./xor2-c < rand.txt 360589110 real 0m2,104s user 0m1,959s sys 0m0,144s time ./xor-cpp < rand.txt 360589110 real 0m29,948s user 0m29,809s sys 0m0,140s time ./xor-cpp-noflush < rand.txt 360589110 real 0m7,604s user 0m7,480s sys 0m0,123sоригинального c++ заняло 30сек код с заняла 2 сек.
даже если
scanfбыстрееcin, это не важно. Подавляющее большинство времени, вы будете читать с жесткого диска или клавиатуры. Получение необработанных данных в приложение занимает на порядки больше времени, чем требуетсяscanfилиcinдля процесса.
конечно, это смешно использовать cstdio над iostream. По крайней мере, когда вы разрабатываете программное обеспечение (если вы уже используете c++ над c, а затем идете до конца и используете его преимущества, а не только страдаете от его недостатков).
но в онлайн-судье вы не разрабатываете программное обеспечение, вы создаете программу, которая должна быть в состоянии делать то, что программное обеспечение Microsoft занимает 60 секунд, чтобы достичь за 3 секунды!!!
Итак, в этом случае золотое правило выглядит так (of конечно, если вы не попадаете в еще больше неприятностей с помощью java)
- используйте c++ и используйте всю его силу (и тяжесть/медлительность), чтобы решить проблему
- если вы получаете ограниченное время, то измените cins и couts для printfs и scanfs (если вы напортачили с помощью строки класса, выполните печать следующим образом: printf(%s,mystr.c_str ());
- если вы все еще получаете ограниченное время, то попробуйте сделать некоторые очевидные оптимизации (например, избегая слишком много встроенных для/while / dowhiles или рекурсивные функции). Также не забудьте пройти мимо ссылочных объектов, которые слишком велики...
- если вы все еще получаете ограниченное время, то попробуйте изменить std::векторы и наборы для C-массивов.
- если вы все еще получаете ограниченное время, а затем перейти к следующей проблеме...
Comments