Używanie scanf() w programach C++ jest szybsze niż używanie cin?

Nie wiem czy to prawda, ale kiedy czytałam FAQ na jednym z problemów z dostarczaniem stron, znalazłam coś, co przyciąga moją uwagę:

Sprawdź swoje metody wejścia/wyjścia. W C++ używanie cin i cout jest zbyt wolne. Użyj ich, a zagwarantujesz, że nie będziesz w stanie rozwiązać żadnego problemu z przyzwoitą ilością danych wejściowych lub wyjściowych. Zamiast tego użyj printf i scanf.

Czy ktoś może to wyjaśnić? Czy używanie scanf () w programach C++ jest szybsze niż używanie cin > > something ? Jeśli tak, to czy jest to dobra praktyka, aby używać go w programach C++? Myślałem, że to C specific, choć dopiero uczę się C++...

Author: Wayne Koorts, 2009-06-25

13 answers

Oto szybki test prostego przypadku: program do odczytu listy liczb ze standardowego wejścia i XOR wszystkich liczb.

Wersja 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;
}

Wersja 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;
}

Wyniki

Używając trzeciego programu, wygenerowałem plik tekstowy zawierający 33 280 276 liczb losowych. Czas realizacji to:

iostream version:  24.3 seconds
scanf version:      6.4 seconds

Zmiana ustawień optymalizacji kompilatora nie zmieniła zbytnio wyników w wszystkie.

Tak więc: naprawdę jest różnica prędkości.

EDIT: użytkownik clyfish wskazuje poniżej , że różnica prędkości wynika głównie z funkcji iostream i/o utrzymujących synchronizację z funkcjami C I/O. Możemy to wyłączyć wywołaniem 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;
}

Nowe wyniki:

iostream version:                       21.9 seconds
scanf version:                           6.8 seconds
iostream with sync_with_stdio(false):    5.5 seconds

C++ iostream wygrywa! okazuje się, że ta wewnętrzna synchronizacja / flushing jest tym, co normalnie spowalnia iostream we / wy. nie mieszając cstdio i iostream, możemy go wyłączyć, a następnie iostream jest najszybszy.

Kod: https://gist.github.com/3845568

 181
Author: nibot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44

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

Wykonanie cin/cout mogą być powolne, ponieważ muszą być zsynchronizowane z podstawową biblioteką C. Jest to niezbędne, jeśli mają być używane zarówno C IO, jak i C++ IO.

Jeśli jednak zamierzasz używać tylko C++ IO, po prostu użyj poniższej linii przed operacjami IO.

std::ios::sync_with_stdio(false);

Aby uzyskać więcej informacji na ten temat, spójrz na odpowiednie libstdc++ docs .

 57
Author: clyfish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 14:01:16

Prawdopodobnie scanf jest nieco szybszy niż używanie strumieni. Chociaż strumienie zapewniają duże bezpieczeństwo typów i nie muszą analizować ciągów formatowych w czasie wykonywania, zwykle ma tę zaletę, że nie wymaga nadmiernej alokacji pamięci(zależy to od kompilatora i środowiska wykonawczego). To powiedziawszy, chyba że wydajność jest twoim jedynym celem końcowym i jesteś na ścieżce krytycznej, powinieneś naprawdę faworyzować bezpieczniejsze (wolniejsze) metody.

Jest tu bardzo pyszny artykuł napisany przez Herb Sutter "The String Formatters of Manor Farm " kto zajmuje się wieloma szczegółami wydajności formaterów łańcuchowych, takich jak sscanf i lexical_cast i jakie rzeczy sprawiały, że działały powoli lub szybko. Jest to coś w rodzaju analogicznego, prawdopodobnie do tego, co miałoby wpływ na wydajność pomiędzy stylem C IO a stylem c++. Główną różnicą w stosunku do formaterów było bezpieczeństwo typu i liczba przydziałów pamięci.

 42
Author: 1800 INFORMATION,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 04:09:17

Właśnie spędziłem wieczór pracując nad problemem na UVa Online (Factovisors, bardzo ciekawy problem, sprawdź to):

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

Otrzymywałem TLE (limit czasu przekroczony) na Moje zgłoszenia. Na tych stronach rozwiązywania problemów Online sędzia, masz około 2-3 drugi limit czasu, aby obsłużyć potencjalnie tysiące przypadków testowych używanych do oceny rozwiązania. Na obliczeniowo intensywne problemy, takie jak ten, liczy się każda mikrosekunda.

Używałem sugerowanego algorytmu (przeczytałem o tym na forach dyskusyjnych dla strony), ale wciąż otrzymywałem TLEs.

Zmieniłem tylko "cin > > n > > m" na " scanf ("%D %d", &n, &m) "i kilka małych" couts "na" printfs", a mój TLE zmienił się w"Accepted"!

Więc tak, może to zrobić dużą różnicę, zwłaszcza gdy terminy są krótkie.

 15
Author: Bogatyr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-12 07:19:50

Wow, mowa o przedwczesnej optymalizacji. Jeśli nie śmieszna optymalizacja. I / O spowoduje zablokowanie Twojego programu na długo przed cin >> x maksymalizacją Twojego procesora quadcore.

Ok, pomijając złośliwość: Nie, Nie jest dobrą praktyką Zamiana <iostream> na <cstdio>. Gdy w C++, użyj bibliotek C++. Nie używaj scanf, nie dzwoń malloc, nie zdaj go, nie zbieraj 200$.

 9
Author: John Kugelman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 04:03:19

Jeśli zależy Ci zarówno na wydajności, jak i formatowaniu łańcuchów, zajrzyj do Biblioteki Fastformat Matthew Wilsona.

Edit -- link do publikacji accu w tej bibliotece: http://accu.org/index.php/journals/1539

 6
Author: xtofl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-16 02:58:55

Tak iostream jest wolniejszy niż cstdio.
Tak, prawdopodobnie nie powinieneś używać cstdio, jeśli rozwijasz się w C++.
Mimo to, istnieją jeszcze szybsze sposoby uzyskania I / O niż scanf, jeśli nie zależy ci na formatowaniu, bezpieczeństwie typu, bla, bla, bla...

Na przykład jest to niestandardowa procedura, aby uzyskać numer ze standardowego wejścia:

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;
}
 3
Author: pedro.lupin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-26 15:17:07

W przypadku plików stdio (libio) Plik* jest implementowany jako C++ streambuf, a fprintf jako Parser formatu runtime. IOstreams nie wymaga przetwarzania formatu runtime, to wszystko odbywa się podczas kompilacji. Tak więc, przy udostępnionych backendach, rozsądne jest oczekiwać, że iostreams jest szybszy w czasie wykonywania.

 2
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-26 09:56:01

Problem polega na tym, że cin ma dużo narzutu, ponieważ daje warstwę abstrakcji powyżej scanf() wywołań. Nie powinieneś używać scanf() nad cin jeśli piszesz oprogramowanie C++, ponieważ do tego jest want cin. Jeśli chcesz wydajności, prawdopodobnie i tak nie piszesz We / Wy w C++.

 1
Author: dreamlax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 04:04:21

Wyrażenia cin i cout w ogólnym użyciu wydają się być wolniejsze niż scanf i printf W C++, ale w rzeczywistości są szybsze!

Rzecz w tym, że w C++ za każdym razem, gdy używasz cin i cout, domyślnie odbywa się proces synchronizacji, który upewnia się, że jeśli używasz zarówno scanf, jak i cin w swoim programie, to oba działają ze sobą zsynchronizowane. Ten proces synchronizacji wymaga czasu. Stąd cin i cout wydają się być wolniejsze.

Jednakże, jeśli proces synchronizacji jest ustawiony aby nie wystąpić, cin jest szybsze niż scanf.

Aby pominąć proces synchronizacji, umieść poniższy fragment kodu w swoim programie na początku main():

std::ios::sync_with_stdio(false);
Aby uzyskać więcej informacji, odwiedź tę stronę .
 0
Author: Prasoon Varshney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-19 10:11:00
#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;
}

Jest błąd na końcu pliku, ale ten kod C jest znacznie szybszy niż szybsza wersja 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

Oryginalny C++ wziął 30sec kod C wziął 2sec.

 0
Author: hexec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-19 06:51:52

Nawet gdyby scanf były szybsze niż cin, nie miałoby to znaczenia. Zdecydowana większość czasu, będziesz czytać z dysku twardego lub klawiatury. Uzyskanie surowych danych do aplikacji zajmuje rząd wielkości więcej czasu niż potrzeba scanf lub cin, aby je przetworzyć.

 -2
Author: Jay Conrod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 04:02:59

Oczywiście używanie cstdio nad iostream jest śmieszne. Przynajmniej kiedy tworzysz oprogramowanie (jeśli już używasz c++ nad c, to idź na całość i korzystaj z jego zalet zamiast cierpieć tylko z jego wad).

Ale w ocenie online nie tworzysz oprogramowania, tworzysz program, który powinien być w stanie robić rzeczy, które oprogramowanie Microsoft zajmuje 60 sekund, aby osiągnąć w 3 sekundy!!!

Więc w tym przypadku złota zasada brzmi tak (oczywiście jeśli nie get into even more trouble by using java)

  • Użyj c++ i użyj całej jego mocy (i ciężkości/powolności), aby rozwiązać problem
  • Jeśli masz ograniczony czas, Zmień cins i couts dla printfs i scanfs (jeśli masz przerąbane używając łańcucha klasy, wydrukuj w ten sposób: printf (%s, mystr.c_str ());
  • jeśli nadal masz ograniczony czas, spróbuj dokonać oczywistych optymalizacji (jak unikanie zbyt wielu osadzonych dla/while/dowhiles lub funkcji rekurencyjnych). Upewnij się również, że aby przejść przez obiekty odniesienia, które są zbyt duże...
  • jeśli nadal masz ograniczony czas, spróbuj zmienić STD::wektory i zestawy dla tablic C.
  • jeśli nadal masz ograniczony czas, przejdź do następnego problemu...
 -3
Author: Carlos Pacheco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-27 02:47:28