본문 바로가기

CS/운영체제

동기와 비동기, Blocking과 Non-Blocking

여러 작업의 수행 방식을 알아보자!

동기 vs 비동기

메소드를 실행시킴과 동시에 반환 값이 기대되는 경우를 동기라고 표현하고 그렇지 않은 경우에 대해서 비동기라고 표현한다. 동시에라는 말은 실행되었을 때 값이 반환되기 전까지는 Blocking되어 있다는 것을 의미한다.

비동기의 경우, Blocking되지 않고 이벤트 큐에 넣거나 백그라운드 스레드에게 해당 task를 위임하고 바로 다음 코드를 실행하기 때문에 기대되는 값이 바로 반환되지 않는다.

 

동기와 비동기의 판단 기준은 두 개 이상의 작업 시간을 맞추는지 아닌지이다.

동기(syncronous)

동기란 여러 작업이 있을 때 서로 시간을 맞춰야 하는 것을 말한다.

먼저 시작 시간 또는 종료 시간을 동일하게 맞추는 경우가 있다 (다중 CPU에서 병렬처리)

또한 하나의 CPU에서는 동시에 하나의 작업만 가능하기 때문에 작업이 끝난 이후 다음 작업을 수행하는 것을 말한다. 이때는 메소드의 리턴과 다음 함수 시작 시간이 같다.

 

비동기(asyncronous)

비동기란 여러 작업이 서로 시간을 맞춰서 실행되지 않는 것이다.

따라서 앞의 작업이 끝날 때까지 기다리지 않아도 된다.

또한 비동기 작업 메소드의 리턴값 반환 시점과 다음 작업 시작 시점이 동일하지 않다. 

 

Blocking vs Non-Blocking

해당 개념은 작업의 제어권이 어디에 있는지가 기준이다.

Blocking은 작업의 제어권이 실행중인 주체에게 있다.

Non-Blocking은 작업의 제어권이 실행을 지시한 주체에게 있다. 직접 제어할 수 없는 대상의 작업처리 여부와 상관없이 동작한다.
예를 들어 호출하는 함수가 I/O 작업을 요청한 뒤 I/O 작업에 대한 처리 완료 여부와 상관없이 바로 자신의 작업을 수행할 수 있는 것을 말한다. 대상의 작업 완료여부와 상관없이 새로운 작업을 수행한다.

 

Blocking

Blocking은 이름에서도 알 수 있듯이 하나의 작업이 실행 중일 때 작업의 제어권이 그 작업에만 있는 것이다.

예를 들어 사용자 영역에서 커널 영역으로 권한이 넘어갔을 때 제어권이 뺏기기 때문에 커널 영역의 작업이 끝날때까지 다른 작업을 할 수 없다. 

 

Non-Blocking

Non-blocking은 반대로 제어할 수 없는 다른 작업이 끝났는지를 상관하지 않는다. 

이것을 I/O 작업으로 빗대자면, 사용자 영역에서 커널 영역으로 제어권이 넘어온 후 작업 완료 여부와 관계없이 Application에게 제어권이 다시 반환된다. (백그라운드 스레드에 해당 task 위임 후)
해당 작업은 커널에서 실행 후 사용자 영역에 결과를 반환한다.

따라서 사용자 영역은 작업을 계속해서 할 수 있고 커널 영역 또한 본인의 작업을 수행하는 것이다.

 

Q. 자바스크립트는 어떤 방식으로 비동기 작업이 진행되나요?

자바스크립트는 싱글 스레드를 사용하며 논블로킹 방식으로 동작한다. 하지만 브라우저는 멀티 스레드로 동작한다. 따라서 일부 코드에 대해 비동기로 동작하게 된다.

비동기 작업이 들어왔을 때 이벤트 큐에 넣고 있다가(비동기) 다시 동기 작업이 진행된다.(제어권 반환하는 논블로킹) 그런 와중에 이벤트 루프가 계속해서 콜스택이 비었는지 확인하고 비었으면 이벤트큐에서 꺼내 콜스택에 넣는다.

큐 자료구조이기 때문에 먼저 들어온 비동기 작업이 먼저 실행된다.

(function () {
  console.log("시작");

  setTimeout(function cb() {
    console.log("콜백 1: 콜백 메시지");
  }); // has a default time value of 0

  console.log("평범한 메시지");

  setTimeout(function cb1() {
    console.log("콜백 2: 콜백 메시지");
  }, 0);

  console.log("종료");
})();

# 시작
# 평범한 메세지
# 종료
# 콜백1: 콜백 메세지
# 콜백2: 콜백 메세지

 

이것은 MDN에서 가져온 자바스크립트의 코드이다.

여기서 setTimeOut 함수는 비동기로 동작하는 함수이다.

즉 해당 함수를 만났을 때 바로 실행하는 것이 아니라 이벤트큐에 넣어놓고 동기작업을 이어서 진행하는 것이다.

이후 동기 작업이 다 끝나면(콜스택이 비면) 이벤트큐에서 비동기 함수를 하나씩 꺼내서 콜스택에 넣는다.

따라서 주석에 써둔 순서대로 출력이 된다.

 

Reference

https://velog.io/@guswns3371/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-Synchronous%EC%99%80-Asynchronous-Blocking%EA%B3%BC-Non-Blocking

https://developer.mozilla.org/ko/docs/Web/JavaScript/Event_loop