자바스크립트를 공부하다보면 동기와 비동기, 그리고 블로킹과 논블로킹에 대해서 마주한적이 분명! 있을거예요.
[동기,비동기] 와 [블로킹,논블로킹] 이 두 개념은 표현 형태는 비슷해 보일지라도, 서로 다른 차원에서 작업의 수행 방식을 설명하는 개념입니다. 동기와 비동기는 요청한 작업에 대해 완료 여부를 신경 써서 작업을 순차적으로 수행할지 아닌지에 대한 관점이고, 블로킹과 논블로킹은 단어 그대로 현재 작업이 block(차단, 대기) 되느냐 아니냐에 따라 다른 작업을 수행할 수 있는지에 대한 관점입니다.
이 두개념에 대한 차이는 명확하지만, 혼용되어 사용되기도 합니다. 대표적으로 자바스크립트의 setTimeout
함수를 일반적으로 비동기 함수라고 부르지만, 동시에 논블로킹 함수이기도 합니다. 즉, 우리가 편의상 부르는 자바스크립트 비동기 함수는 사실 비동기 + 논블로킹 함수인 것입니다.
📌 동기(Synchronous) / 비동기(Asynchronous)
먼저 동기란, 작업시간을 함께 맞춰서 실행한다는 뜻입니다. 작업을 맞춰서 실행한다는 뜻은 요청한 작업에 대해 완료 여부를 따져 순차적으로 처리하는 것을 말합니다. 반대로 비동기는 요청한 작업에 대해 완료 여부를 따지지 않기 때문에 자신의 다음 작업을 그대로 수행하게 됩니다.
이미지와 같이 동기는 작업 B가 완료되어야 다음 작업을 수행하고, 비동기는 작업 B의 완료 여부를 따지지 않고 바로 다음 작업을 수행합니다.
📌 비동기 성능의 이점
비동기는 대체로 특징을 이용하여 성능과 함께 연관지어 말합니다. 왜냐하면 요청한 작업여부를 따지지 않고 자신의 그 다음 작업을 수행한다는 것은 느린 작업이 발생했을 때, 기다리지 않고 동시에 다른 작업을 처리하는 멀티작업을 진행할 수 있기 때문입니다.
여기서 '동시 처리'라는 개념은 두 개이상의 작업이 동시에 실행되는 것을 말합니다. 이는 멀티 스레드나 멀티 프로세싱과 같은 방식으로 구현될 수 있다고 합니다. 예를 들어, 자바스크립트 같은 경우 비동기로 작업을 요청하면 브라우저에 내장된 멀티 스레드로 이뤄진 Web API에 작업이 인가되어 메인 Call Stack
과 작업이 동시에 처리되게 됩니다.
대표적인 비동기 작업의 종류로는 애니메이션 실행, 네트워크 통신, 마우스 키보드 입력, 타이머 등이 있습니다.
다만 자바스크립트 코드 실행 자체는 Web API가 아닌 Call Stack
에서 실행됩니다.
(코드 실행은 콜스택에서 이뤄지지만, 작업처리는 Web API)
📌 동기와 비동기는 작업 순서의 차이
동기작업은 요청한 작업에 대해 순서가 지켜지는 것을 말하고, 비동기 작업은 순서가 지켜지지 않을 수 있다는 것을 말합니다.
예를 들어, A, B, C라는 작업을 요청했을 경우에, 동기 방식으로 처리하면 A -> B -> C 순서대로 실행하게 되고, 비동기 방식으로 처리하게 되면 A -> C -> B 또는 C -> A -> B 등 무작위 순서로 실행하게 됩니다.
정리하자면 작업 3개를 요청했는데 응답에서 그 순서가 지켜진다면 동기이고 어떤 게 먼저 올지 모른다면 비동기라고 보면 됩니다.
📌 Blocking / Non-Blocking
블로킹과 논블록킹은 단어에서 알 수 있듯이 다른 요청의 작업을 처리하기 위해 현재 작업을 block(차단, 대기) 하냐 안하냐의 유무를 나타내는 프로세스의 실행 방식입니다.
동기/비동기가 전체적인 작업에 대한 순차적인 흐름 유무라면, 블로킹/논블로킹은 전체적인 작업의 흐름 자체를 막냐 안 막냐로 볼 수 있는 것입니다.
예를 들어, 파일을 읽는 작업이 있을 때, 블로킹 방식으로 읽으면 파일을 다 읽을 때까지 대기하고, 논블로킹 방식으로 읽으면 파일을 다 읽지 않아도 다른 작업을 할 수 있게 됩니다.
예를들어 아래 코드는 setTimeout 함수를 사용하여 1초 후에 "Hello, world!"를 출력하는 비동기 논블로킹 코드의 예제입니다. 코드를 실행하면, "시작"과 "끝"이 먼저 출력되고, 1초 후에 "1초 후에 실행됩니다!"가 출력되게 됩니다.
console.log("시작");
setTimeout(() => {
console.log("1초 후에 실행됩니다!");
}, 1000);
console.log("끝");
출력결과 > "시작" > "끝" > "1초 후에 실행됩니다!"
위와 같은 결과가 나오는 이유는 setTimeout
함수에 대해 타이머 작업 완료 여부를 신경 쓰지 않고 바로 그 다음 콘솔 작업을 수행하였기 때문입니다. 그리고 setTimeout 함수의 타이머 작업 완료 알람을 콜백 함수를 통해 값을 받아 출력하였다. 따라서 setTimeout 은 비동기(Asynchronouse)입니다.
다른 시각으로 보면 메인 함수 작업에 대해서 setTimeout 함수는 자신의 타이머 작업을 수행하기 위해 메인 함수를 블락하지 않고 백그라운드에서 별도로 처리되었다. 메인 함수를 블락하지 않으니 setTimeout 함수를 호출하고 바로 그 다음 콘솔 함수를 호출한 것이다. 따라서 setTimeout
은 논블로킹(Non-blocking)입니다.
📌 누가 제어권을 가지고 있느냐
제어권은 간단히 말해서 함수의 코드나 프로세스의 실행 흐름을 제어할 수 있는 권리라고 볼 수 있습니다. 즉, Blocking과 Non-Blocking은 호출된 함수(callee)가 호출한 함수(caller)에게 제어권을 바로 주느냐 안주느냐로 구분됩니다. 제어권이 넘어가버리면 해당 스레드는 블로킹되게 됩니다.
다음은 A 함수와 B 함수 작업에 대해 A 함수가 B 함수를 Blocking 방식으로 호출할시 제어권 상태를 나타낸 그림입니다.
다음은 A 함수와 B 함수 작업에 대해 A 함수가 B 함수를 Non-Blocking 방식으로 호출할시 제어권 상태를 나타낸 그림입니다.
📌 동기/비동기 + 블로킹/논블로킹 조합
🧐 Sync Blocking 조합
동기-블로킹 조합은 다른 작업이 진행되는 동안 자신의 작업을 처리하지 않고, 다른 작업의 완료 여부를 바로 받아 순차적으로 처리하는 (Sync) 방식입니다.
- 실생활 동작 예시
카페에서 손님이 커피를 주문하면, 점원은 손님을 받고, 음료를 만든다.
그 뒤에 있는 손님은 앞의 손님의 주문과 음료가 다 만들어질 때까지 아무것도 할 수 없다. 기다려야한다.
이러한 동기-블로킹 은 코드가 순차적으로 실행되는 특성을 가지고 있습니다. 그래서 Sync Blocking 조합은 일반적으로 작업이 간단하거나 작업량이 적은 경우에 사용됩니다. 하지만 작업량이 많거나 시간이 오래 걸리는 작업을 처리해야 하는 경우에는 동기-블로킹 방식을 사용하면 독이 됩니다. 왜냐하면 작업을 처리하면 작업이 끝날 때까지 다른 작업을 처리하지 못하므로, 전체 처리 시간이 오래 걸리게 되어 비효율적이기 때문입니다.
🧐 Async Non-Blocking 조합
비동기-논블로킹 조합은 다른 작업이 진행되는 동안에도 자신의 작업을 처리하고 다른 작업의 결과를 바로 처리하지 않아 작업 순서가 지켜지지 않는 (Async) 방식입니다.
- 실생활 동작 예시
- 팀장 : 사원1씨 A업무좀 해주세요. (동시에 지시)
- 팀장 : 사원2씨 B업무좀 해주세요. (동시에 지시)
- 팀장 : 사원3씨 C업무좀 해주세요. (동시에 지시)
- 팀장 : 다른일을 해야지 ~
- 사원2 : 팀장인 B 모두 처리했습니다. (업무량에 따라 각 사원마다 완료하는 시간이 제각기 다를 수 있다)
- 사원1 : 팀장인 A 모두 처리했습니다.
- 사원3 : 팀장인 C 모두 처리했습니다.
이처럼 Async Non Blocking 조합은 작업량이 많거나 시간이 오래 걸리는 작업을 처리해야 하는 경우에 적합합니다. 예를 들어, 대용량 데이터를 처리하거나 많은 요청을 처리하는 서비스에서는 비동기-논블로킹 방식을 사용하여 한 작업이 처리되는 동안 다른 작업을 처리할 수 있으므로 전체 처리 시간을 줄일 수 있어 어플리케이션 처리 성능을 향상시킬 수 있게 됩니다.
- 활용 예시 프로그램
비동기 논블로킹을 활용하는 프로그램은 많이 있습니다. 그중 예를 들자면, 웹 브라우저의 파일 다운로드가 비동기 논블로킹을 활용하는 예시 라고 할 수 있습니다. 웹 브라우저는 웹 사이트에서 파일을 다운로드할 때, 파일의 전송이 완료될 때까지 다른 작업을 하지 않고 기다리는 것이 아니라, 다른 탭이나 창을 열거나 웹 서핑을 할 수 있다. 이는 웹 브라우저가 파일 다운로드를 비동기적으로 처리하고, 콜백 함수를 통해 다운로드가 완료되면 알려주는 방식으로 구현되어 있기 때문입니다.
이외에 동기-논블로킹은 자바스크립트에서 구현하기 어려운 개념이고, 비동기와-블로킹은 실제 실무에서 거의 쓰이지 않는다고 합니다.🥲 찾아본 여러 아티클에서도 동기-논블로킹은 모두 JAVA언어로 구현되어있어서 설명을 생략합니다.