hyunjin

ios::sync_with_stdio , cin.tie , cout.tie 사용법과 설명, 속도 비교 본문

개인 공부/C++

ios::sync_with_stdio , cin.tie , cout.tie 사용법과 설명, 속도 비교

_h.j 2020. 8. 13. 17:05
728x90

※요약 : 아래 구문들을 사용할 때, C와 C++의 입출력 혼용하지 않아야하며, thread 사용에 주의해야한다.

 

1.ios_base::sync_with_stido(bool sync);

[설명]

C++ 표준 스트림들이 C표준 스트림들과 각각의 입출력 연산 후에 동기화 여부 설정
false : C 표준 stream과 C++ 표준 stream의 동기화를 끊는다.
리턴값 : 함수 호출하기 전 이전의 동기화 상태

 

[sync 비교]

sync : true

기본적으로, 모든 표준 stream들은 동기화 되어있다.

동기화된 C++ stream들이 자신의 버퍼 대신 C++ stream의 입출력 연산들이

이에 대응되는 C stream 버퍼를 사용

 C와 C++의 입출력 방식을 자유롭게 혼용 가능

 

또한 동기화된 C++ stream들은 thread-safe (안정성 보장)한다.

여러 쓰레드에서 각각 출력 연산을 수행할 수 있지만, 경쟁 상태(race condition) 발생하지 않음.

(  다른 thread의 output이 동시에 액세스해도 충돌하지 않는다.)

 

sync : false

동기화를 끊는다면, C++ stream은 독립적인 버퍼를 갖게 되어

C와 C++의 입출력 방식 혼용하여 쓰는 것이 위험

=> 입출력 객체 섞어 사용하는 경우 출력 순서를 보장하지 않아 오답처리 가능성 있음

multi-thread의 경우 Thread-unsafe해지기 때문에 예상치 못한 겂이 나올 수 있음

 

 

 

[속도 비교]

동기화를 끊으면 사용하는 버퍼의 수가 줄어들어 실행속도 자체는 크게 향상된다.

 

cin, cout이 scanf,printf에 비해 속도가 많이 느리다.

std::endl 보다 '\n'이 훨씬 빠르다.

입력값 개수가 100만개 이상 시 확연하게 차이난다.

결론적으로 편리함 때문에 cin,cout 쓰기 보단 scanf와 printf 사용

좀 더 빠르게 하겠다면 글자 하나씩 입출력하는 함수들이 더 빠르다.(getchar,putchar 등등)

 

동기화를 끊고 cin,cout을 사용한다 하더라도 속도를 가속할 수는 있지만 정공법은 아니고, 이 방식 통하지 않는 경우가 있음.

 

굳이 sync_with_stdio(false) 사용해 C++ 입출력 객체 가속시킨다면

- scanf와 printf 섞어 사용하지 말기

- 싱글 쓰레드 환경에서만 사용(알고리즘 문제 풀 때는 무조건 싱글이긴 하지만 실무에선 아님)

 

 

 

 

[ios_base::sync_with_stido 의 실행 예제]

#include <cstdio>
#include <iostream>

using namespace std;

int main(){
	ios::sync_with_stdio(false);
    cout << "a\n";
    
    //동기화 되어 있지 않아 b가 먼저 혹은 나중에 출력된다.
    printf("b\n");
    cout<< "c\n";
}

실행 결과

b
c
a

입출력 순서 보장x

 

 

2. cin.tie, cout.tie

[설명]

ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin을 cout으로 부터 풀어준다.(untie)
stream을 tie 하면 다른 stream에서 입출력 요청 오기 전에 stream을 먼저 flush 시킨다.

 

[tie, untie 비교]

cout<< "enter name : ";
cint >> name;

tie

program이 user에게 입력을 요구하기 전에 output이 flush됨

 

 

untie

위의 코드 실행 시 untie 되어있다면 output이 flush되지 않은 채로 user에게 입력요구

따라서 콘솔 상에서 Enter name이 출력되지 않는다.

(그러나 vs 상에서 돌려보니 정상적으로 출력됨, 왜인지는 모른다.)

 

기본적으로 cout의 output은 buffer가 가득차거나 수동적으로 flush 되기 전까진 출력되지 않음.

그러므로 untie시 , cin으로 입력 받기전 뭔가를 띄우고 싶다면 매번 수동적으로 

cout을 flush 시켜줘야함.

 

 

[속도]

실제 백준에서 여러 알고리즘 돌려보면 cin,cout  unite 시 출력 500만번 기준 8ms 속도 상승

 

 

 

3. 그 외

stream buffer : 데이터를 내보내거나 받아들이기 전에 임시로 저장하는 곳

예를 들어서 우리가 하드디스크에서 파일을 하나 읽는다고 해봅시다. 만일 사용자가, 1 바이트 씩 읽는 다고 했을 때, 실제로 프로그램은 1 byte 씩 읽는 것이 아닙니다.

실제로는 한 뭉터기 (예를 들어서 512 바이트) 를 한꺼번에 읽어서 스트림 버퍼에 잠시 저장해 놓은 뒤에 사용자가 요청할 때 마다 1 바이트 씩 꺼내는 것이지요. 만일 버퍼를 다 읽는다면 다시 하드에서 512 바이트를 읽게 되는 것입니다. 이렇게 수행하는 이유는, 하드디스크에서 읽어오는 작업이 매우 느리기 때문에, 한 번 읽을 때 1 바이트 읽으면 엄청난 딜레이가 발생하게 됩니다. 이는 쓰는 작업에서도 마찬가지 입니다. 쓸 때도 우리가 1 문자를 출력 하게 되면, 하드에 바로 쓰는 것이 아니라 일단 버퍼에 보관한 후, 어느 정도 모인 뒤에 출력하게 됩니다.

 

flush()
현재 버퍼에 저장되어 있는 내용을 클라이언트로 전송하고 버퍼를 비운다.(jsp)
출력 스트림과 버퍼된 출력 바이트를 강제로 사용하게 한다.

 

buffer가 다 차기 전에 프로그램 종료하면 buffer에 들어있는 내용은 파일에 쓰여지지 않고

그 때 flush()를 호출하면 buffer의 내용이 파일이 쓰여진다.

 

flush는 다음에 더 자세히 다루도록 하자.

 

참고 사이트, 출처

sync_withstdio 설명1 바로가기

sync_with_stdio 설명2 바로가기

cin,cout.tie 설명 바로가기

 

 

728x90

'개인 공부 > C++' 카테고리의 다른 글

[씹어먹는 C++]< 1- C++> namespace  (0) 2021.03.02
int , string , char 형 변환  (0) 2021.02.16
isalpha , isdigit , isalnum  (0) 2021.02.16
2진수 <-> 10진수 변환 코드, bitset  (0) 2020.09.04
출력 포맷 변경 iomanip  (0) 2020.09.01