본문 바로가기

Dev.World/개발상식&언어

blocking, non-blocking and Async

blocking, non-blocking and Async

Blocking I/O Model
일단 I/O작업은 User Level(application)에서 직접 수행할 수 없다. 실제 I/O작업은 Kernel Level(OS)에서 일어나는 과정이다. 따라서 유저 프로세스(applicatioin)는 커널(OS)에게 I/O 작업에 대한 요청을 해야 한다. I/O 작업을 처리하기 위해 User Level에 있던 Application이 시스템 함수를 호출한다.(system call) 이 때 context-switching 이 발생한다. 그리고 Kernel Level에서 해당 I/O 작업이 끝나고 데이터를 반환하게 되면 그 때가 되서야 애플리케이션 단의 스레드에 걸렸던 block이 풀린다. 애플리케이션 관점에서 보면 아무런 동작도 안하는 것처럼 (마치 렉이 걸린 것처럼)보이지만 실제로는 커널에서 I/O 작업을 수행하느라 block되어 있는 것이다. 바로 이 부분이 blocking IO의 문제점이며 개선 포인트이다.

Synchronous, Blocking IO 의 비교
Synchronous(동기)
작업을 요청한 후 해당 작업의 결과가 나올 때까지 기다린 후 처리하는 것으로 I/O작업에 대한 readiness를 기다린다. 특정 I/O작업을 하기 위한 준비가 되었는지에 집중하는 것이다. I/O 작업 준비에 대한 이벤트의 발생을 기다렸다가 해당 이벤트가 발생하면 그에 따른 적합한 처리를 한다.

Blocking
I/O가 끝날 때까지 대기해야 한다. 끝나기 전에는 함수가 반환(return)되지 않기 때문이다. 커널이 작업을 완료하기 전까지 유저 프로세스는 작업을 중단한 채 대기해야 한다. IO작업이 CPU자원을 거의 쓰지 않기 때문에 blocking 방법은 cpu 자원 낭비가 심하다.

즉 동기화하기 위해 blocking 하는 것이다.

synchronous vs blocking
시스템의 반환을 기다리는 동안 대기 큐에 머무는 것이 필수가 아니면 synchronous
시스템의 반환을 기다리는 동안 대기 큐에 머무는 것이 필수이면 blocking
둘 다 시스템의 반환을 기다린다는 측면에서 synchronous와 blocking은 같은 개념이다.

Non-blocking I/O Model

앞서 설명한 Blocking I/O방식은 요청한 I/O작업이 끝날 때까지, 완료될 때까지 대기해야 한다. 끝나기 전에는 반환(return)되지 않기 때문이다. 그렇기 때문에 커널이 작업을 완료하기 전까지 유저 프로세스는 작업을 중단한 채 대기해야 한다. I/O작업은 CPU자원을 거의 쓰지 않기 때문에 blocking 방법은 cpu 자원 낭비가 심하다. 이러한 blocking방식의 비효율성을 극복하고자 만들어진 것이 non-blocking 방식이다. non-blocking 방식은 I/O작업을 진행하는 동안 유저 프로세스의 작업을 중단시키지 않는다. 유저 프로세스가 I/O를 처리하기 위해 커널에 함수를 호출하면(system call), 커널에서 함수의 진행 상황과 상관없이 바로 결과를 반환한다. 이 때 반환되는 결과는 반환하는 순간에 가져올 수 있는 데이터에 해당한다. 처음에는 가져올 수 있는 데이터가 없겠지만 시간이 지나면서 가져올 수 있는 데이터가 생겨날 것이다.

이렇게 되면 서버는 클라이언트가 요청한 사이즈에 맞는 데이터를 반환하기 위해 데이터를 축적해야 한다. 데이터의 축적이 끝났을 때, 반환되어 클라이언트에서 요청한 사이즈의 데이터를 받아올 수 있게 된다.  하지만 이 구현 방식의 문제는 클라이언트가 따로 반환되는 값이 원하는 사이즈가 되었는지 계속해서 확인해줘야 한다는 것이다.(polling) 반환되는 데이터가 준비되었는지(원하는 값이 되었는지) 확인하는 과정에서 수많은 클라이언트의 요청이 동시 다발적으로 일어날 경우, CPU에게 적지 않은 부담이 될 수 있는 I/O Model이다.

blocking vs non-blocking
애플리케이션 실행 시 운영체제 대기 큐에 들어가면서 요청에 대한 system call이 완료된 후에 응답을 보낼 경우 blocking
애플리케이션 실행 시 운영체제 대기 큐에 들어가지 않고 실행 여부와 관계없이 바로 응답을 보낼 경우 non-blocking


Asynchronous I/O


event-driven model
이벤트 통지 모델이라고도 부르는 이 모델은 Non-blocking에서 제기된 문제를 해결하기 위해 고안되었다. Non-blocking I/O Model에서처럼 애플리케이션에서 데이터가 준비되었는지 계속해서 확인하는 것이 아니라, kernel Level에서 데이터가 데이터가 준비되면 콜백 또는 이벤트를 발생시켜 애플리케이션에 알리게 된다.(notify) User Level에서의 애플리케이션 스레드는 계속해서 데이터가 준비되었는지 확인할 필요없이 다음 작업을 수행하다가 커널에서 이벤트가 발생하게 되면 그 작업에 해당하는 일을 처리해주면 되는 것이다. 

Asynchronous (비동기)
작업을 요청해놓고 딴 일을 하다가 해당 작업이 완료되면 그 때 완료되었음을 통지받고 그에 따른 작업을 처리하는 것을 말한다. I/O 작업의 completion을 기다린다. 운영체제 단계의 비동기 API를 통해 이루어지며 IO작업이 completion이 되면 그에 적합한 Handler를 이용해 처리를 한다.

synchronous vs asynchronous
system call의 완료를 기다리면 synchronous
system call의 완료를 기다리지 않으면 asynchoronous

non-blocking vs asynchronous
system call이 반환될 때 실행된 결과(데이터)와 함께 반환될 경우 non-blocking
system call이 반환될 때 실행된 결과(데이터)와 함께 반환되지 않는 경우 asynchronous
조금 더 덧붙이자면, asynchronous 방식은 데이터를 콜백 함수 또는 이벤트, signal로 전달하게 되는 것이며, non-blocking 방식은 매 system call return에 데이터가 포함되어, return 되는 데이터가 요청한 데이터가 전부 도달했는지를 파악하게 된다.


Reference>>


end