Kim-Baek 개발자 이야기

[카카오 면접] Blocking I/O, Syncronous Non-Blocking I/O, Asyncronous Non-Blocking I/O 본문

개발

[카카오 면접] Blocking I/O, Syncronous Non-Blocking I/O, Asyncronous Non-Blocking I/O

김백개발자 2020. 8. 6. 10:31
카카오 면접을 준비하면서, 공부했던 내용을 정리해놓고 다시 기억하기 위한 포스팅

다른 관심사

Blocking-Sync가 비슷하고, NonBlocking-Async가 비슷하지만, Blocking/NonBlocking과 Sync/Async이 2:2 매트릭스 그림에서 각각 다른 축에 자리잡는 데는 이유가 있다. 두 그룹은 관심사가 다르다. 

Blocking/NonBlocking

Blocking/NonBlocking은 호출되는 함수가 바로 리턴하느냐 마느냐가 관심사다. 

호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른 일을 할 수 있는 기회를 줄 수 있으면 NonBlocking이다.

그렇지 않고 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수에게 제어권을 넘겨주지 않고 대기하게 만든다면 Blocking이다.

Synchronous/Asynchronous

Synchronous/Asynchronous는 호출되는 함수의 작업 완료 여부를 누가 신경쓰냐가 관심사다.

호출되는 함수에게 callback을 전달해서, 호출되는 함수의 작업이 완료되면 호출되는 함수가 전달받은 callback을 실행하고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않으면 Asynchronous다.

호출하는 함수가 호출되는 함수의 작업 완료 후 리턴을 기다리거나, 또는 호출되는 함수로부터 바로 리턴 받더라도 작업 완료 여부를 호출하는 함수 스스로 계속 확인하며 신경쓰면 Synchronous다.

 

 

NonBlocking-Sync

앞에서 살펴본대로 조합해보면 NonBlocking-Sync는 호출되는 함수는 바로 리턴하고, 호출하는 함수는 작업 완료 여부를 신경쓰는 것이다. 신경쓰는 방법이 기다리거나 물어보거나 두 가지가 있었는데, NonBlocking 함수를 호출했다면 사실 기다릴 필요는 없고 물어보는 일이 남는다. 

즉, NonBlocking 메서드 호출 후 바로 반환 받아서 다른 작업을 할 수 있게 되지만, 메서드 호출에 의해 수행되는 작업이 완료된 것은 아니며, 호출하는 메서드가 호출되는 메서드 쪽에 작업 완료 여부를 계속 문의한다. 

그림을 그려보면 다음과 같다.

이런 케이스가 뭐가 있을까 생각해보니 future.isDone()이 이것과 비슷한 것 같다.

Future ft = asyncFileChannel.read(~~~);

while(!ft.isDone()) {
    // isDone()은 asyncChannle.read() 작업이 완료되지 않았다면 false를 바로 리턴해준다.
    // isDone()은 물어보면 대답을 해줄 뿐 작업 완료를 스스로 신경쓰지 않고,
    //     isDone()을 호출하는 쪽에서 계속 isDone()을 호출하면서 작업 완료를 신경쓴다.
    // asyncChannle.read()이 완료되지 않아도 여기에서 다른 작업 수행 가능 
}

// 작업이 완료되면 작업 결과에 따른 다른 작업 처리

참고로 위 코드는 NonBlocking-Sync라는 특성 이해에 집중할 수 있도록 간략화한 예제고, 실무적으로는 Future보다는 CompletableFuture를 쓰거나, Future를 쓴다면 위의 while 블록은 별도의 쓰레드로 빼서 실행하는 것이 좋다.

 

Blocking-Async

앞에서 살펴본대로 조합해보면 Blocking-Async는 호출되는 함수가 바로 리턴하지 않고, 호출하는 함수는 작업 완료 여부를 신경쓰지 않는 것이다.

그림을 그려보면 다음과 같다.

이런 사례는 사실 생각해봐도 금방 떠오르는 게 없다. 어차피 Blocking되어 대기하는 것 외에는 다른 일도 못 하게된 마당에, 그냥 작업 끝날 때까지 기다렸다가 결과를 반환 받아서 처리하는 Blocking-Sync 방식과 성능적으로 거의 차이가 나지 않을 것 같은 방식이라서가 아닐까..

글을 올리고 보니 다른 분께서 좋은 의견을 주셨다. Blocking-Async는 별로 이점이 없어서 일부러 이 방식을 사용할 필요가 없기는 한데, 의도하지 않게 Blocking-Async로 동작하는 경우가 있다고 한다. 원래는 NonBlocking-Async를 추구하다가 의도와는 다르게 실제로는 Blocking-Async가 되어버리는 경우라고 하는데 그것은 바로..

Blocking-Async의 대표적인 케이스가 Node.js와 MySQL의 조합이라고 한다.

Node.js 쪽에서 callback 지옥을 헤치면서 Async로 전진해와도, 결국 DB 작업 호출 시에는 MySQL에서 제공하는 드라이버를 호출하게 되는데, 이 드라이버가 Blocking 방식이라고 한다. 

이건 사실 Node.js 뿐아니라 Java의 JDBC도 마찬가지다. 다만 Node.js가 싱글 쓰레드 루프 기반이라 멀티 쓰레드 기반인 Java의 Servlet 컨테이너보다 문제가 더 두드러져 보일 뿐, Blocking-Async라는 근본 원인은 같다.

그래서 Blocking-Async는 이렇게 정리해도 좋을 것 같다.

Blocking-Async는 별다른 장점이 없어서 일부러 사용할 필요는 없지만, 

NonBlocking-Async 방식을 쓰는데 그 과정 중에 하나라도 Blocking으로 동작하는 놈이 포함되어 있다면 의도하지 않게 Blocking-Async로 동작할 수 있다.

반응형

'개발' 카테고리의 다른 글

[카카오 면접] JAVA 10, 11, 12  (0) 2020.08.10
[카카오 면접] Garbage Collector 의 여러 방법  (0) 2020.08.07
JPA와 Spring Data JPA  (0) 2020.08.05
JPA Fetch 전략과 N+1 문제  (0) 2020.08.05
JPA란? ORM vs SQL Mapper  (0) 2020.08.04
Comments