코드네임 JY

[C++] iostream을 사용하고도 코드 속도를 높이고 싶다면? 본문

알고리즘 공부

[C++] iostream을 사용하고도 코드 속도를 높이고 싶다면?

영재임재영 2022. 12. 4. 23:56

메모리와 시간 차이

필자는 C++을 활용하여 백준 문제들을 풀고 있다.

예전에 풀었던 문제들을 다시 풀어보는 와중에 흥미로운 사실 하나를 발견했다.

 

위 코드는 cstdio 를 선언하여 scanf / printf 를 활용하여 입출력을 받았고,

아래 코드는 iostream을 선언하여 cin / cout 을 활용하여 입출력을 받았다.

 

 

메모리적 측면

헤더파일을 다르게 씀으로써 발생하는 메모리적 차이는 크게 중요하지 않다고 한다.

수십~수백의 메모리 차이가 발생하지 않기도 하고, 위 문제는 약 1MB 정도의 차이가 발생했다.

 

 

시간적 측면

오히려 시간적 측면에서는 짚고 넘어가야 할 사항들이 좀 있다.

 

백준에서 여러 언어와 입력 방법이 입출력하는데 얼마의 시간이 소요되는지 분석한 글이 있다.

(https://www.acmicpc.net/blog/view/56)

위 글에서는 stdio.h를 활용한 C에서는 0.9초, iostream을 활용한 C++에서는 2.1초가 나왔다.

 

입출력 속도의 차이는 버퍼 때문이다

cin과 cout이 느린 이유는 C 라이브러리의 stdio 버퍼와 동기화하는 과정 때문이다.

iostream과 stdio의 버퍼를 모두 사용한다는 뜻이다.

그렇다면 stdio 버퍼를 끊어주면 iostream만 사용하기 때문에 시간이 줄어들지 않을까?

 

이는 ios_base::sync_with_stdio() 구문을 통해 구현할 수 있다.

ios_base::sync_with_stdio() 구문은 C의 stdio와 C++의 iostream을 동기화하게 해준다.

괄호 안에 false 값을 넣게 되면, 동기화를 비활성화 할 수 있게 된다.

따라서 C++ 만의 독립적인 버퍼를 사용할 수 있게 되고, 실행 속도도 빨라지게 된다.

 

하지만 ios_base::sync_with_stdio() 구문에 false 값을 넣게 될 경우,

멀티 쓰레딩을 할 수 없다.

알고리즘 문제를 풀 때는 멀티 쓰레딩을 사용하지 않으므로 문제가 되진 않지만,

멀티 쓰레딩을 사용해야하는 환경에서 위 구문을 사용하면

C와 C++의 입출력을 번갈아 사용할 수 없다.

예상하지 못한 결과나 출력 순서가 나올 수 있기 때문이다.

 

실무의 경우에는 멀티 쓰레딩을 사용하는 경우가 있다.

따라서 위 방법을 쓸 경우, 멀티 쓰레딩에 적절하지 않다.

이는 입출력 속도를 빠르게 하고 싶기 때문에 사용하는 일종의 편법이다.

 

cin, cout 의 속도도 제어하고 싶다면?

cin.tie(NULL) 구문과 cout.tie(NULL) 을 사용하면 입출력 속도를 더 빠르게 할 수 있다.

기본적으로 cin과 cout은 하나로 묶여 있는데, 대표적인 예제로 설명을 하겠다.

 

cout << "Input number : ";

cin >> name;                       

 

위 코드의 경우 cin과 cout이 묶여있어 입력을 받기 전에 cout에 걸린 구문이 먼저 출력된다.

하지만 묶음을 풀면 cout의 구문이 출력되지 않았는데도 입력을 먼저 받는 경우가 생긴다.

따라서 콘솔 상에 cout의 구문이 출력되지 않는다. (이론적으론 안 되는게 맞나, 대부분 된다.)

 

알고리즘 문제를 풀 때는 콘솔에 즉각적으로 보이는 것은 중요하지 않다.

입출력을 번갈아가며 수행해야 할 경우, 묶음을 풀면 시간이 훨씬 줄어들 것이다.

따라서 이는 극한으로 속도를 높이고 싶은 경우에 사용하는 하나의 편법이다.

(참고 : 실제 백준에서 위 방법들을 사용하면 속도가 많이 상승한다고 한다.)

 

개행 문자도 속도에 영향을 미친다

C++ 내에서 endl 은 출력 함수의 끝을 알리고, 버퍼를 정리하는 기능을 한다.

버퍼를 정리하는 기능으로 인해, 출력하는 시간에 딜레이가 발생할 수 있다.

따라서 endl 보다 \n 을 통해서 개행을 진행하는 것도 시간을 줄일 수 있는 하나의 팁이 된다.

 

결론

ios_base::sync_with_stdio(false);

cin.tie(NULL); cout.tie(NULL);

알고리즘 문제를 풀 때에 한해서만 사용하고, scanf / printf 를 같이 사용하지 않도록 주의하자!

그래도 시간 초과가 발생한다면, 그냥 scanf / printf 를 사용해서 정공법으로 문제를 풀자!

Comments