fast IO를 알기 전에, 먼저 IO가 어떻게 동작하는지 알 필요가 있습니다.
output은 상용 프로그램이 일반적인 operation을 사용해서 할 수 있는 것이 아니기 때문에, OS에 system call로 요청을 하게 됩니다. 이것은 프로그램의 실행 주권이 내가 쓴 프로그램에 있다가 OS로 넘어가고, OS가 output을 진행하는 동안 프로그램은 기다리고 있다가, 응답(이 경우에는 "잘 출력되었음")이 돌아오면 다시 프로그램을 진행합니다.
문제는 system call은 아주 오래 걸리는 작업이라는 것입니다. 특히 출력의 경우, "a"를 화면에 출력하고 "b"를 화면에 출력하는 것이 "ab"를 화면에 출력하는 것과 크게 다르지 않다면, 프로그래머가 출력을 원할 때마다 system call을 하지 말고, 출력해야 할 내용을 계산만 해 두고 메모리 어딘가에 저장해 두었다가 한꺼번에 출력하면 훨씬 빠르게 실행할 수 있을 것입니다. 이는 printf
나 puts
등이 사용하고 있는 방법입니다. 이때 저장해 두는 메모리 공간은 특별히 buffer라고 부릅니다.
cstdio
가 사용하는 buffer의 기본 크기는 1024입니다. 출력해야 할 내용이 상당히 많다면, buffer를 더 크게 잡고 싶을 것입니다. 아쉽게도 PS에서 원하는 정도로(예를 들어 1048576 정도로) 이 기본 buffer를 훨씬 크게 늘려 잡을 수 있는 방법은 없습니다. 그렇지만 buffer에 쌓아 두는 작업과 system call을 날리는 작업은 일반적인 프로그램에서도 할 수 있기 때문에, printf를 사용하지 않고 그것을 직접 구현하면 system call의 횟수를 비약적으로 줄일 수 있습니다. fast IO는 이 모든 과정을 직접 구현해서 속도를 빠르게 하려는 방법입니다.
입력도 마찬가지입니다. buffer에 입력을 미리 전부 받아 놓고 필요할 때마다 연산만 해서 쓰면 system call의 횟수를 비약적으로 줄일 수 있습니다. 입력 파일은 pts(pseudo-terminal slave)에 연결되어 있는 경우 조금 다르게 동작하는데, 관련된 내용이 궁금하시다면 이 단어로 검색해 보시기 바랍니다.
iostream
을 사용하시는 분들이 std::endl
을 사용하지 않는 이유 역시 설명할 수 있는데, 이는 타자기 시절의 유물입니다. 한 줄을 강제로 끝내는 것(carriage-return, line-feed)은 그 줄은 더 이상 수정할 수 없음을 의미하기 때문에, 컴퓨터에서는 이 줄을 강제로 끝내고, buffer를 출력하고 비우는 system call을 날립니다(=flush). 그래서 줄의 수가 많으면 비정상적으로 느려지게 됩니다. 대신 '\n'
을 출력하면 이것은 그냥 문자를 하나 출력하는 행동이기 때문에 flush를 하지 않게 됩니다.
qktlf789456 3년 전
많이 사용하시는 fast io 의 원리가궁금해요!