Contents

동기 비동기 블로킹 논블로킹

운영체제, 어플리케이션에서는 한정된 리소스를 효율적으로 사용하고 커널 - 어플리케이션 간 통신에서 효율적으로 데이터를 교환하기 위한 몇 가지 방식이 있다.

동기 - 비동기의 차이점

동기 - 비동기의 차이점은 작업 완료 되는 대상에 있다.

  • 동기 : 작업 완료를 호출한 녀석이 확인
  • 비동기 : 작업 완료를 콜백 함수가 확인

블로킹 - 논블로킹의 차이점

블로킹 - 논블로킹의 차이점은 호출 대상이 리턴하는 시점에 있다. 즉 작업에 대한 제어 권한이 다르다.

  • 블로킹 : 호출된 녀석이 바로 리턴하지 않고 작업이 완료된 이후에 리턴. 호출한 녀석이 책임지고 작업을 끝까지 수행
  • 논블로킹 : 호출된 녀석이 바로 리턴. 호출한 녀석이 호출된 녀석에게 작업에 대한 권한을 이양

어떤 것을 써야 할까

2 * 2 이므로 총 4가지의 조합이 가능하다.

  1. 동기 - 블로킹
  2. 동기 - 논블로킹
  3. 비동기 - 블로킹
  4. 비동기 - 논블로킹

취업 준비를 하며 공부할 때에도 이 중 1번과 4번인 동기 - 블로킹과 비동기 - 논블로킹은 잘 와닿았다.

동기 - 블로킹

전공생 입장에서 가장 많이 접해본 방식이 아닐까 생각한다. 태초의 전통적이고 아주 오래된 프로그래밍 방식이고, 비효율적이기에 여러 방식을 섞으려는 시도가 있어왔다.

비동기 - 논블로킹

이벤트 방식 또는 Spring Webflux 등에서 사용하는 방식이다. Spring Webflux도 작업에 대한 권한을 이벤트 루프 그룹에게 이양하고, 콜백으로 작업에 대한 결과를 받는다. 자바스크립트의 프로미스, Async / Await 등을 생각하면 쉽다.

비동기 - 블로킹과 동기 - 논블로킹은 왜 쓸까

https://developer.ibm.com/articles/l-async/ 자료를 참고했다.

비동기 - 블로킹

비동기 - 블로킹 방식을 요약하자면 작업의 주체를 호출 대상에 넘기되, 호출 대상이 작업을 다 마칠 때까지 호출자가 아무런 동작을 하지 않는 것이다.

비동기 - 블로킹 방식은 명령을 하지 않는 포켓몬 배틀이다. 트레이너인 내가 포켓몬을 꺼내 상대와 대결을 하는데, 내 포켓몬에게 아무런 명령도 내리지 않고 알아서 싸우라고 하는 것이다. 나는 내 포켓몬이 잘 싸우고 있는지는 별로 궁금하지 않아서 내 포켓몬에게 다 끝나면 나를 부르라고 하는 것이다. 대신 내 포켓몬이 싸우고 있는 동안에는 나는 아무런 동작도 할 수 없다.

  • 중간에 화장실을 갈 수도 없고 (포켓몬 배틀에서는 상대방을 존중해야 하므로)
  • 다른 포켓몬을 꺼내서 상대에게 다구리를 칠 수도 없다. (이미 나와서 싸우고 있는 포켓몬이 속상해 한다)

이런 방식이 언제 유용할까? 아무리 생각해봐도 효율적인 케이스가 많이 없을 것 같다. 작업자에게 작업을 시켜놓고 작업이 끝나기 전까지 나는 아무것도 못하고 기다리는데 효율적일 수가 있을까? 라는 생각이 들었다 그런데 의도치 않게 이 방식으로 동작할 수는 있다.

Node.js + MySQL의 조합의 경우,

  • Node.js는 Asynchronous 하게 작업을 수행한다.
  • MySQL의 innoDB 엔진은 Blocking 방식으로 동작한다.

동기 - 논블로킹

동기 - 논블로킹 방식을 요약하자면 작업의 주체는 호출자가 계속 가지고 있지만, 작업 완료의 기준은 호출 대상이 정한다. 동기 - 논블로킹 방식은 비동기 - 블로킹 방식과 유사하지만 약간 다르다.

동기 - 논블로킹 방식은 데일리 스크럼에 비유할 수 있을 것 같다. 일의 주체는 회사 (팀)가 가지고 있다. 하지만 작업 완료의 기준은 팀에 소속된 작업자들이 가지고 있다. 일의 주체는 매일 아침 회의를 통해 작업이 얼마나 완료되고 있는지 확인한다. 작업이 완료되면 작업자들이 일의 주체가 아침 회의에서 물어봤을 때 끝났다고 대답한다.

이런 방식이 언제 유용할까? future.isDone()과 비슷..

논블로킹이라는 전제에서 작업 자체가 즉시 끝나지 않는다는 것을 의미하기 때문에 어플리케이션이 작업이 완료되기를 기다리며 작업 수행자에게 여러 번 물어보는 것이다.

대부분의 경우 어플리케이션이 작업의 결과물 또는 데이터가 준비될 때까지는 busy wait 상태로 진입하기 때문에 굉장히 비효율적일 수 있다. 동기 - 논블로킹 IO 모델에서는 커널에서 가용한 데이터와 반환하기 위해 읽기를 호출하는 사용자 사이의 간극이 전체 데이터 처리량을 감소시킬 수 있기 때문에 IO에 대기 시간을 추가로 도입하게 했다.

리눅스의 select()

멀티 플렉싱 모델을 사용하는 동기-논블로킹 IO이다. 체크할 파일 디스크립터 목록을 배열로 만들어놓고 select()에서 반환되면 순회하면서 데이터를 처리한다.