동기 / 비동기 VS Blocking / Non-Blocking

Jiwan Ahn·2023년 12월 22일
0
post-thumbnail

들어가며

개발자들 사이에서 가장 많이 헷갈리는 것 중 하나가 동기와 비동기, 그리고 Blocking과 Non-Blocking 의 구분인 것 같다. 심지어 둘이 다르다는 것을 알긴 해도, 그 이유에 대해서는 또 잘 모르거나, 잘못 알고 있는 경우가 있다.

필자 또한 둘의 개념을 공부하면서 "엥? 그게 그거 아닌가?" 라고 생각했었지만, 자세히 뜯어보면 아예 다른 개념인 것을 알 수 있었다.

이번 글에서는 쉬운 예시와 함께 둘 사이의 분명한 차이점에 대해 다룰 것이다.


Synchronous VS Asynchronous

동기 (Synchronous)

어떤 작업을 실행할 때, 요청한 작업이 완료되었는지 여부를 따지며 순차적으로 처리한다.

예시)
어떤 빵을 만들기 위해, “반죽을 오븐에 넣어 빵을 만들기” → “야채를 썰어 빵을 꾸밀 데코레이터 준비” → “오븐에 구워진 빵에 데코레이터 장식” 이라는 프로세스가 있다고 하자.

동기적으로 처리하면 다음과 같다.

  • 반죽을 오븐에 넣고, 5분 타이머를 설정한 후, 반죽이 빵이 될 때까지 기다린다.
  • 5분이 지나고 빵을 꺼낸다.
  • 그 후, 야채를 썰어 데코레이터를 준비한다.
  • 빵에 데코레이터를 얹어 빵을 완성한다.

즉, 오븐에서 5분 타이머를 걸어 빵이 완전히 구워질 때 기다리고, 완성될 때 다음 과정인 야채를 썰어 데코레이터를 준비한다.

비동기 (Asynchronous)

어떤 작업을 실행할 때, 요청한 작업의 완료 여부를 신경쓰지 않고 처리한다.

위의 예시를 비동기적으로 처리해보자.

  • 반죽을 오븐에 넣고, 5분 타이머를 설정한다.
  • 오븐에 반죽이 구워질 동안, 야채를 썰어 데코레이터를 준비한다.
  • 5분 타이머가 지나 “띵” 하고 소리가 나면, 빵을 꺼낸다.
  • 이미 준비한 데코레이터를 빵 위에 얹어 빵을 완성한다.

비동기 방식의 요리는 오븐에서 5분 타이머를 걸고 그 동안 동시에 야채를 썰어 미리 데코레이터를 준비한다. 즉, 빵이 오븐에서 구워지는 것과 무관하게 다른 작업을 한다.

그렇다면 Blocking, Non-Blocking의 차이는 뭘까?

Blocking VS Non-Blocking

Blocking

: 어떤 작업을 실행할 때, “제어권”을 호출한 함수에게 넘겨주어, 그 함수가 완료될 때 까지 다른 작업을 막는다.

Blocking의 관점에서 다시 요리해보자.

  • 반죽을 오븐에 넣고, 5분 타이머를 설정한다.
  • 오븐이 반죽에 구워질 때까지, 아무것도 하지 않고 멍 때리며 기다린다.
  • 5분이 지나고 빵을 꺼낸다.
  • 그 후, 야채를 썰어 데코레이터를 준비한다.
  • 빵에 데코레이터를 얹어 빵을 완성한다.

억양의 차이가 있다. 즉, 오븐이 반죽에 구워질 동안, “아무것도 하지 않는다”는 것이 Blocking의 핵심이다. 요리는 온전히 오븐에 빵이 구워지는 것에 전적으로 결정되는 것이다.

Non-Blocking

: 어떤 작업을 실행할 때, 함수를 호출하되 “제어권”을 넘기지 않고, 다른 작업을 동시에 한다.
Non-Blocking 관점에서 다시 요리해보자.

  • 반죽을 오븐에 넣고, 5분 타이머를 설정한다.
  • 그 후, 오븐에 “신경을 끄고” 야채를 썰어 데코레이터를 미리 준비한다.
  • “띵” 하고 타이머가 완료되면 그 때 빵을 꺼내어 데코레이터를 얹어 빵을 완성을 한다.

이 역시, 오븐이 반죽에 구워질 동안, 오븐에 “신경을 쓰지 않는다”는 것이 Non-Blocking의 핵심이다. 즉, 요리의 단계는 이 오븐에 빵이 구워지는 것과 관계없이 계속 진행되는 것이다.

즉, 동기와 비동기, blocking과 non-blocking의 결정적인 차이는, 중심이 되는 내용이 “작업 순서”인지, 아니면 “제어권”인지, 그 차이에 있다.

따라서 이 개념을 정확하게 알고 있으면 sync-nonBlocking, async-blocking이 어떻게 이루어지는지 이루어질 수 있다.


Sync-NonBlocking

  • 반죽을 오븐에 넣고, 5분 타이머를 설정한다.
  • 그 후, “멍 때리지 않고” 30초에 한 번씩 타이머를 확인하면서 빵의 상태도 확인한다.
  • 5분 타이머가 끝나 빵이 다 구워지면, 야채를 썰어 데코레이터를 만든다.
  • 만든 데코레이터를 빵에 얹어 빵을 완성을 한다.

즉, 일단 빵이 오븐에 넣어질 때 까지 야채를 써는 “후속 작업”을 하지는 않지만, 여전히 주기적으로 타이머를 확인하거나, 빵의 상태도 확인하는 등의 “다른 작업”을 실행할 수 있다.

실제 이 점이 사용되는 점은 게임 내의 로딩창이라고 할 수 있다.

게임이 준비되기 까지 계속 기다려도, 로딩창을 새로고침 하는 "또 다른 작업"을 수행하도록 하기 위해서는 Sync-NonBlocking을 사용한다.

Async-Blocking

: 이 방식은 흔히 개발자의 실수에서 발생해서 “안티 패턴”이라고 불리기도 한다. 왜 인지는 이 예시를 통해 확인할 수 있다.

  • 반죽을 오븐에 넣고, 5분 타이머를 설정한다.
  • 다른 작업을 하려는 순간, 오븐이 갑자기 나에게 마법을 걸어 “아무것도 못하게 만든다.”
  • 다른 작업을 할 수 있음에도, 나는 이 마법 때문에 아무것도 못한다. 즉, 제어권이 오븐에게 넘어가버렸다.
  • 5분 타이머가 끝나면 “오븐이 나에게 걸린 마법을 해제하고” 비로소 난 움직여 빵을 꺼낼 수 있다.
  • 그 후, 야채를 썰어 데코레이터를 완성하고 빵을 완성한다.

이렇게 분명 비동기적으로 다른 작업을 할 수 있는데, 내 몸의 제어권이 오븐에게 넘어가서 다른 작업을 할 수 없게 된다는 것이다.


결론

보통의 경우, 동기와 Blocking을 동일시 하고 비동기와 Non-Blocking을 동일시 하는 경향이 있다. 그러나, 둘이 함께 같이 쓰긴 해도 호출한 함수 (Callee)가 작업을 완료할 때 까지 대기를 하는지, Callee에게 제어권을 넘겨 본 함수의 제어권이 소실되는지, 이 여부에 따라 동기/비동기, Blocking/Non-Blocking을 구분하는 점이 가장 큰 차이라고 할 수 있겠다.

profile
Engineer, to be a Pioneer.

0개의 댓글