[JS] 블로킹과 논블로킹, 동기와 비동기

steven semyung oh·2023년 5월 31일
2

비동기여행

목록 보기
1/4

본 시리즈를 비롯한 블로그에 작성된 글은 저의 학습 목적으로 작성되었습니다. 글은 자의적인 해석과 함께 엉망진창으로 만들어졌을겁니다. 그렇지만 리팩토링을 하면서 더 나은 구현체를 만드는 과정을 글을 쓰는데에도 적용하려고 합니다. 학습을 통해 꾸준히 업데이트를 하여 학습을 하시는 분들께 좋은 참고자료가 되기를 희망합니다.

작업이라는 단어

이 글에서 섹션에 가장 많이 나오는 단어는 작업이다. 계산, 데이터 조작, i/o 연산 등 세상에서 존재하는 작업의 종류는 참 많다. 우리의 상상력이 곧 작업으로 이어지니깐 말이다. 하지만 아래 섹션에서 사용될 작업은 우리의 상상력을 표현하는 방법을 염두하였다. 우리의 상상력을 이용해서 수행하는 작업들을 컴퓨터는 statement, expression, 또는 function으로 해석하기 때문이다. (우리가 노력하고 있다는 것을 컴퓨터가 알면 얼마나 좋을까?)

그리고 자의적인 잣대로 작업의 종료와 작업의 완료를 구분지었다. 이는 function으로 구현된 작업에 대해서 논블로킹과 비동기를 좀 더 명료하게 설명하고 싶었기 때문이다. 이 잣대는 분명한 한계가 있다.

작업의 종료는 함수의 실행이 종료되었음을 뜻한다. void 로 끝나거나, 특정 타입으로 리턴된다.
작업의 완료는 함수 내부에서 '작업'이라고 불리는 것이 완료되었음을 뜻한다.

Blocking vs Non-Blocking

두 단어는 Block이라는 단어를 공통적으로 사용하고 있다. 이 단어의 사전적인 의미는 다음과 같다.

If you block something that is being arranged, you prevent it from being done.

이 단어가 내포하는 뉘앙스는 주체가 대상에 대해 뭔가를 못하게 한다는 것이다. 이 뉘앙스를 자바스크립트 세계에 적용하면 어떨까? 자바스크립트 세계에서 블로킹/논블로킹은 작업이 완료될 때까지 다른 작업을 중단시키는지 여부를 나타내는 개념이다.

Blocking

function sleep(ms: number) {
  const wakeUpTime = Date.now() + ms;
  while (Date.now() < wakeUpTime) {}
}
sleep(2000);
console.log("done");

어떤 작업이 완료될 때까지 다른 작업을 중단시키는 상황을 블로킹이라고 한다. 함수단위로 바라본다면, 작업이 완료될 때까지 제어권을 반환하지 않는다. 프로그램(caller)은 해당 작업이 완료되기를 기다리며, 그동안 아무런 작업을 수행하지 않는다. 이런 의미에서 볼 때 console.log("done") Statement 역시 Blocking Code라고 말할 수 있다.

Non-Blocking

이 단어는 접두사 Non이 붙은 것으로 쉽게 유추가 가능하다. 어떤 작업이 완료될 때 까지 다른 작업을 중단시키지 않는 상황을 논블로킹이라고 한다. 함수단위로 바라본다면, 작업의 완료와 관계없이 제어권을 즉시 반환한다. 다음의 코드를 보자.

const { readFile } = require('fs');

readFile('./01.txt', 'utf8', (err, data) => {
  if (err) {
    throw err;
  }
  console.log(data); // {2}
});
console.log('hi'); // {1}

프로그램은 readFile() 호출문을 먼저 실행하게 된다. 이 함수는 Node.js에서 제공하는 API로, 제어권을 즉시 돌려주고 경로에 지정된 파일을 읽는 연산을 C++ 구현체에 등록하고 작업을 종료한다. 이후 작업이 완료되었다면 3번째 인자에 전달된 콜백함수를 결과를 인자로 전달하여 호출한다.
readFile() 은 작업의 완료시점, 즉 콜백함수가 호출되는 시점이 작업의 종료시점보다 더 나중이다. 논블로킹은 작업의 종료시점과 관계가 있다.

Synchronous vs Asynchronous

이 두 단어는 Synchronous라는 단어를 공통적으로 사용하고 있다. 애석하게도 이 단어의 사전적 뉘앙스와 자바스크립트 세계에서 사용되는 뉘앙스는 다른듯 하다. 리서치를 하면서 많은 관점과 관점들이 서로 충돌하는 모습을 많이 보았다. 나는 그중 통신의 맥락에서 동기화(Synchronization)라는 개념에서 뉘앙스를 찾을 수 있다는 내용이 재밌게 다가왔다. 이 내용을 번역해보면 다음과 같다.

동기화(Synchronization)는 통신에서 다음의 의미를 갖습니다.
1. 수신기가 메시지를 받을 준비가 되었다면, 준비가 되었음을 알리는 시그널을 보냅니다.
2. 송신기는 수신기에서 전달된 시그널을 받은 다음부터 송신을 시작합니다.
3. 송신기가 메시지를 모두 보내었다면, 메시지 전송이 완료되었음을 알리는 시그널을 보냅니다.
4. 수신기는 전달받은 메시지를 통해 다음 작업을 실행합니다.

송신기와 수신기는 시그널을 가지고 서로 의존적인 관계를 가지고 있다. 그리고 어느 한쪽에서 작업(Task)가 완료되고 난 다음 시그널을 보내면 반대쪽에서 이후 작업을 하는 것을 알 수 있다. 이 개념을 가지고 자바스크립트 세계에서 Synchronous의 의미를 추론해보면 어떨까? 참고로 이 추론의 결과는 동기와 비동기의 개념의 일부분일 뿐이다. 글들을 많이 보면서 명료한 단어로 표현하기는 아직까지 어려운 것 같다. 🥲

Synchronous

const a = 1; // {1}
console.log(a); // {2}
const b = 2; // {3}
const c = 3; // {4}

자바스크립트 세계에서 2번 코드가 실행되는 때는 1번 코드의 실행이 완료된 다음이다. 각 Task의 시작 시점은 그 전 Task를 완료하는 시점과 동기화된다. 다시말해 전에 실행되었던 문이 끝나기 전까지는 다음 문을 실행할 수 없다. 실행의 측면에서 볼 때 하나의 Task가 완료되는 지점과 다음 Task가 실행되는 지점이 동기화되어 프로그램이 실행되는 것을 동기(동기적 처리)라고 한다.

동기적 코드(Synchronous code)는 완료와 실행 시점이 동기화된 코드, 다시말해 동기적으로 처리되는 코드를 의미한다.

function getRandomNumber() {
  return Math.random();
}

const x = getRandomNumber();
console.log(x);

getRandomNumber() 처럼 하나의 Task의 완료시점(난수를 만드는 동작)이 함수가 끝나는 시점과 동기화되었다면, 이 함수를 동기적으로 동작하는 코드라고 부르기도 한다.

Asynchronous

이 단어는 Synchronous에 접두사 a를 붙인 단어이다. 접두사 a는 without, lack of의 의미를 가지므로, Not Synchronous를 뜻한다. 실행의 측면에서 볼 때 Task의 시작 지점과 그 전 Task의 완료 시점이 동기화되지 않고 프로그램이 실행되는 것을 비동기(비동기 처리)라 한다.

비동기 코드, 비동기 함수 등과 같은 비동기 작업 은 비동기적으로 실행되는 코드를 의미한다.

앞서 보았던 NodeJS의 예시를 다시 보자.

const { readFile } = require('fs');

readFile('./01.txt', 'utf8', (err, data) => {
  if (err) {
    throw err;
  }
  console.log(data); // {2}
});
console.log('hi'); // {1}

자바스크립트 엔진은 프로그램을 실행할 때 readFile()console.log() 를 순차적으로 실행한다. 로깅은 1. 전역스코프, 2. 콜백 함수의 함수스코프 순으로 이루어진다. readFile() 에서 수행하는 연산은 작업의 종료와 관계 없다. 나중 시점에 작업의 결과물을 확인할 수 있다.

리즈너블한 질문들

  1. 논블로킹이나 비동기 처리가 들어간 코드에서 콜백함수는 항상 실행의 종료보다 늦게 실행되는가? 더 일찍 실행될 수 있지 않은가?
  2. 블로킹이나 동기적 처리가 들어간 코드는 제어권을 프로그램이 잘 가지고 있는 듯하다. 그런데 논블로킹/비동기 처리가 들어간 코드의 제어권은 도대체 누구한테 있는 것인가? 프로그램의 실행 순서가 제대로 보장되지 않는 것 같은데, 이 문제를 해결할 수 있는 방법은 없는 것일까?

이 질문들에 대한 답변은, 차후 블로그 작성 글에서 다뤄보고자 한다.

profile
네명입니다

0개의 댓글