Blocking I/O와 Nonblocking I/O의 차이가 무엇인지 궁금해 읽게 됐습니다.
논블로킹 I/O에 대해 얘기하기 전 왜 네트워크 I/O에서 논블로킹을 사용하는지에 대해서 설명합니다.
How does the caller of a non-blocking/asynchronous API gets notified when data is ready? How does this work under the hood, at low level? 어떻게 비동기 논블로킹 API 호출자가 데이터가 준비되었을 때 알림을 받을 수 있을까요? 로우 레벨에서는 무슨 일이 일어나는 걸까요?
하드 드라이브, 네트워크, 데이터베이스와 수행하는 IO 인터렉션 작업들은 일반적으로 CPU가 IO 작업을 호출한 뒤에는 다른 작업이 발생하지 않습니다. IO로부터 데이터를 요청하는 API를 호출했을 때, 아마 응답을 곧바로 받지 못하고 그 사이에 딜레이가 있을테죠. 물론 이런 딜레이는 하드 드라이브에서 파일을 요청했을 때는 아주 짧지만, 네트워크에서는 이보다 훨씬 깁니다.
- *하드 드라이브에 저장되어있는 파일들은 SATA 케이블과 메인보드 버스를 통해 CPU로 전송됩니다.
IO로부터 데이터를 요청하는 API를 호출하는 것은 실행중인 스레드를 블락 상태로 만듭니다. 리눅스에서는 스레드가 블락되면, 커널에 의해서 호출자에게로 데이터가 반환될 때 까지 sleep 상태로 들어가게 됩니다.
sleep 상태의 스레드들은 즉시 CPU 제어권을 포기하게 되기때문에 CPU 타임을 낭비하지 않습니다. IO가 준비된 뒤에는 스레드는 sleep 상태로부터 벗어나고 runnable 상태로 들어가게 됩니다. 이 상태에 있는 스레드들은 CPU에 실행 가능한 상태로 들어가게 되죠. 이렇게 CPU에게 스레드를 배분하며 on/off를 조작하는 행위를 컨텍스트 스위칭이라고 합니다.
스레드는 다른 상태를 가질 수 있습니다. 여러 언어나 OS에서 각각 상태를 부르는게 다르며, 리눅스 커널에서는 running, not running이 존재하고 자바 스레드에서는 6개의 상태가 있습니다.