Использование scanf() в программах на С++ быстрее, чем использование cin?

Я не знаю, верно ли это, но когда я читал FAQ по одной из проблем, связанных с сайтами, я нашел что-то, что заставило меня обратить внимание:

Проверьте свои методы ввода/вывода. В С++ использование cin и cout происходит слишком медленно. Используйте их, и вы гарантируете, что не сможете решить любую проблему с приличным количеством ввода или вывода. Вместо этого используйте printf и scanf.

Может кто-то прояснить это? Действительно ли использует scanf() в программах на С++ быстрее, чем использование cin → something? Если да, то это хорошая практика, чтобы использовать его в программах на С++? Я думал, что это C специфический, хотя я просто изучаю С++...

Ответ 1

Вот быстрый тест простого случая: программа для чтения списка чисел из стандартного ввода и 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 I/O, поддерживающими синхронизацию с функциями ввода/вывода 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 seconds

С++ iostream выигрывает! Оказывается, что эта внутренняя синхронизация/промывка - это то, что обычно замедляет iostream i/o. Если мы не смешиваем cstdio и iostream, мы можем отключить его, а затем iostream будет быстрее.

Код: https://gist.github.com/3845568

Ответ 2

http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma

Производительность cin/cout может быть медленной, поскольку они должны синхронизироваться с базовой библиотекой C. Это важно, если будут использоваться как C IO, так и С++ IO.

Однако, если вы собираетесь использовать только С++ IO, просто используйте приведенную ниже строку перед любыми операциями ввода-вывода

std::ios::sync_with_stdio(false);

Для получения дополнительной информации об этом ознакомьтесь с документами libstdС++: http://gcc.gnu.org/onlinedocs/libstdc++/manual/io_and_c.html

Ответ 3

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

Существует очень вкусная статья, написанная здесь Хербом Саттером " The String Formatters of Manor Farm", который подробно излагает производительность строковых форматировщиков, таких как sscanf и lexical_cast, и какие вещи делали их медленными или быстрыми. Это похоже на аналогичные, возможно, на то, что может повлиять на производительность между стилем я стиля C и стилем С++. Основное различие с форматировщиками, как правило, было типом безопасности и количеством распределений памяти.

Ответ 4

Я просто провел вечер, работая над проблемой на UVa Online (Factovisors, очень интересная проблема, проверьте это):

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=35&page=show_problem&problem=1080

Я получал TLE (превышение лимита времени) по моим представлениям. На этих проблемах, связанных с сайтами онлайн-судей, у вас есть 2-3-секундный срок, чтобы обрабатывать потенциально тысячи тестовых случаев, используемых для оценки вашего решения. Для таких интенсивных вычислительных задач, как этот, каждый микросекунд считается.

Я использовал предложенный алгоритм (читал об этом в дискуссионных форумах для сайта), но все еще получал TLE.

Я изменил только "cin → n → m" на "scanf" ( "% d% d", & n, & m) "и несколько крошечных" выводов "на" printfs ", а мой TLE превратился в" Принято"!

Итак, да, это может иметь большое значение, особенно когда сроки ограничены.

Ответ 5

Ничего себе, поговорим о преждевременной оптимизации. Если не смешная оптимизация. Ввод/вывод будет узким местом для вашей программы задолго до того, как cin >> x максимизирует ваш процессор Quadcore.

ОК, сдержанность в сторону: Нет, это не хорошая практика, чтобы поменять <iostream> на <cstdio>. В С++ используйте библиотеки С++. Не используйте scanf, не вызывайте malloc, не проходите, не собирайте $200.

Ответ 7

Да, iostream медленнее, чем cstdio.
Да, вы, вероятно, не должны использовать cstdio, если вы работаете на С++.
Сказав это, есть даже более быстрые способы ввода I/O, чем scanf, если вам не нужны форматирование, введите безопасность, blah, blah, blah...

Например, это обычная процедура для получения номера из 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;
}

Ответ 8

Существуют реализации stdio (libio), который реализует FILE * как потоковый файл С++, а fprintf - как синтаксический анализатор времени исполнения. Для IO-потоков не требуется синтаксический анализ формата выполнения, который выполняется во время компиляции. Таким образом, с общим доступом к бэкендам, разумно ожидать, что iostreams будет быстрее во время выполнения.

Ответ 9

Проблема заключается в том, что cin имеет много накладных расходов, потому что это дает вам уровень абстракции выше вызовов scanf(). Вы не должны использовать scanf() над cin, если вы пишете программное обеспечение на С++, потому что для этого требуется cin. Если вам нужна производительность, вы, вероятно, не будете писать ввода-вывода на С++.

Ответ 10

#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 значительно быстрее, чем более быстрая версия cpp.

[email protected] 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

исходный cpp был 30 секунд, это 2 секунды.

Ответ 11

Операторы cin и cout в общем использовании кажутся медленнее, чем scanf и printf в С++, но на самом деле они являются FASTER!

Дело в том, что в С++, когда вы используете cin и cout, по умолчанию выполняется процесс синхронизации, который гарантирует, что если вы используете как scanf, так и cin в своей программе, то они оба работают синхронно друг с другом. Этот процесс синхронизации требует времени. Следовательно, cin и cout APPEAR будут медленнее.

Однако, если процесс синхронизации не установлен, cin работает быстрее, чем scanf.

Чтобы пропустить процесс синхронизации, включите следующий фрагмент кода в свою программу в начале main():

std::ios::sync_with_stdio(false);

Посетите этот сайт для получения дополнительной информации.

Ответ 12

Даже если scanf быстрее, чем cin, это не имеет значения. Подавляющее большинство времени, вы будете читать с жесткого диска или клавиатуры. Получение необработанных данных в ваше приложение занимает на порядок больше времени, чем требуется scanf или cin для его обработки.

Ответ 13

Конечно, смешно использовать cstdio над iostream. По крайней мере, когда вы разрабатываете программное обеспечение (если вы уже используете С++ поверх c, то идите полностью и используйте его преимущества, а не только страдаете от его недостатков).

Но в онлайн-судьи вы не разрабатываете программное обеспечение, вы создаете программу, которая должна быть способна делать то, что программное обеспечение Microsoft занимает 60 секунд, чтобы достичь через 3 секунды.

Итак, в этом случае золотое правило идет (конечно, если вы не получите еще больше проблем с помощью java)

  • Используйте С++ и используйте всю его мощность (и тяжесть/медленность), чтобы решить проблему.
  • Если вы ограничены по времени, измените cins и couts для printfs и scanfs (если вы нажмете с помощью строки класса, напечатайте вот так: printf (% s, mystr.c_str());
  • Если у вас все еще ограниченное время, попробуйте сделать некоторые очевидные оптимизации (например, избегать слишком много встроенных для /while/dowhiles или рекурсивных функций). Также убедитесь, что вы перешли по ссылочным объектам, которые слишком велики...
  • Если у вас все еще ограниченное время, попробуйте изменить std::vectors и установите для c-массивов.
  • Если у вас все еще ограниченное время, переходите к следующей проблеме...