본문 바로가기

Programming/C++

C++ 입출력 속도 증가(알고리즘 대회)

일반적으로 std::cin 과 std::cout 의 속도가 C언어의 scanf(), printf()보다 느리다는 것은 모두가 알고 있는 사실이다.

다만 C언어로 이용하든, C++로 이용하든 scanf()와 printf()함수는 잘 사용하지 않는 다는 것이다. 여러 이유가 있지만, 가장 큰 이유들은 보안상의 이유거나, 문자열을 다루는데 불편함이 많아 잘 사용하지 않는다. 

 

그래서 std::cin과 std::cout 사용을 포기하지 않고, 입출력 속도를 높일 방법을 정리한다.

(단, 이 방법도 Race Condition이 발생할 수 있으므로, Test용도나 알고리즘 대회 등 실무와는 관계가 없는 상황에서 사용하는 것을 권한다.)

 

추가적으로 빠른 입출력에 대해서 알고 싶다면, c++ fast i/o로 검색하면 많은 정보를 얻을 수 있다.

 

  • ios_base::sync_with_stdio(false)

기본적으로는 ios_base::sync_with_stdio(true)로 설정되어 있다.

이름에 sync가 보이는 만큼 synchronize(동기화)임을 쉽게 유추할 수 있다. 

ios_base::sync_with_stdio는 표준 C++의 입출력 stream이 표준 C stream과 동기화 여부를 설정할 수 있다.

 

표준 C++ stream: std::cin, std::cout, std::cerr, std::clog, std::wcin, std::wcout, std::wcerr, std::wclog

표준 C stream    : stdin, stdout, stderr

 

C++ stream이 C stream과 동기화 되어 있다는 것은, C++ stream의 모든 입출력이 각각 대응되는 C stream을 이용한다는 것이다. 어떤 computer science이든 "동기화"라는 말이 붙으면, 속도가 느리다. 다만 C++ stream과 C stream이 동기화 됨으로서, C++ 입출력과 C 입출력을 혼합해서 사용하더라도, 정상적으로 정해진 순서에 따라 입출력이 진행된다.

추가적으로 스레드를 사용할 때 Data Race Condition이 발생하지 않기 때문에, 보다 안정적인 스레드 사용이 가능하다.

 

위와는 반대로 동기화를 끄면, C++ 표준 입출력 stream이 버퍼를 이용하여, 독립적으로 입출력할 수 있기 때문에 입출력 속도가 상승하는 효과를 볼 수 있다. 또한 C stream과의 동기화를 끊는 것이기 때문에, 입출력을 사용할 때 C stream 입출력과 C++ stream 입출력 둘다 사용해서는 안된다.

 

 

  • cin.tie(NULL)

기본적으로는 std::cout 과 std::cin은 tie() 상태이다.

tie()상태일 경우, 입력을 받기 전에 출력 버퍼를 flush 한다. cin.tie(NULL)은 출력 버퍼를 비우지 않도록 한다.

당연한 얘기이지만, std::cout은 buffer가 차거나, flush를 하지 않으면, 출력을 하지 않는다.

따라서 알고리즘 대회나 Test용도로만 적합하며, 실무에서는 사용하지 않는 것이 좋다.

 

 

  • \n

std::endl은 output stream의 버퍼를 비우기 때문에 \n보다 느리다. 

다만, 헷갈리기 쉬운 부분은 존재한다.

표준에 따르면 \n은 출력버퍼를 비우지 않는다. 하지만 많은 구현체(implementations)가 \n을 출력할 때 출력 버퍼를 비우도록 설계되어 있다.

 

std::endl은 output stream을 비우지만, \n은 buffered output을 비우기 때문에 속도 차이가 발생한다.

 

#출처 및 참고

en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio

en.cppreference.com/w/cpp/io/manip/endl

www.quora.com/What-is-the-difference-between-stream-I-o-and-buffered-I-o-in-C++-and-C