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++...
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.
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 .
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.
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):
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.
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$.
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
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;
}
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.
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++.
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ę .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.
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ć.
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...
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