✅ 이 글의 예시와 설명은 얄팍한 코딩사전을 참고하였습니다
드림 코딩으로 자바스크립트를 공부하며 비동기에 대해 찍먹을 하긴 했는데, 자바스크립트 엔진에서 어떻게 비동기가 처리되는지에 대한 것은 잘 몰랐다. 이번에 알아봄!!
비동기 작업에 대해 공부하기 전에, 프로세스와 스레드에 대한 개념을 알아본다. 비동기를 이해하기 위함 외에도 동시성 프로그래밍을 위해 알고있어야 하는 개념이라고 한다!
여기 한 식당이 있다고 하자. 맛집으로 소문나 수많은 손님들이 쏟아져 들어오고 있는데...
손님들이 주문한 메뉴를 처리하는 것을 프로세스라고 한다.
메뉴 하나당 하나의 프로세스가 할당된다. 컴퓨터에서 하나의 프로그램이 실행되면 하나의 프로세스를 돌린다라고 말한다.
컴퓨터는 프로세스를 동시적으로도 돌릴 수 있고, 병렬적으로도 돌릴 수 있고, 두 방법을 혼합하여 돌릴 수도 있다.
4개의 메뉴에 대한 주문(프로세스)가 있다고 할 때,
동시적으로 돌리는 것은 한 명의 요리사가 4개의 메뉴를 차례대로 조금씩 조금씩 하면서 순회하는 것을 말한다. 컴퓨터의 경우에 이 속도가 굉장히 빠르기 때문에 사용자는 4개의 프로세스가 동시에 실행된다고 받아들이게 된다. 설명을 딱 들었을 땐 선점형 프로세스 스케줄링 알고리즘 중 하나인 라운드 로빈이 생각나는데 맞는지 모르겠다.
병렬적으로 돌리는 것은 한 명의 요리사가 아닌, 4명의 요리사가 각각의 메뉴를 담당하는 것을 말한다. CPU가 물리적 발열의 문제로 발전이 더뎌지자, 여러 코어를 붙이는 식을 채택하게 되었는데 이 코어 각각이 한 명의 요리사인 것. 쿼드코어, 옥타코어 등이 있다.
프로세스 안에서도 여러 갈래로 나뉠 수 있다. 예를들어 주문한 메뉴가 라면이라면
이런 작업들이 이어질 것이고, 이런 각각의 작업을 스레드라고 한다.
같은 메뉴를 만들 때는 같은 자원을 공유하는 것이 더 효율적이다. 라면 만드는 데 필요한 스레드를 삼겹살 굽는 프로세스에서 처리한다면 비효율적일 것이다. 따라서 여러 프로세스가 있을 때 각각의 프로세스에는 컴퓨터가 각각의 자원을 할당하지만, 스레드는 프로세스마다 주어진 전체 자원을 함께 사용한다.
함께 사용하여 발생하는 문제점도 있다. 공유되는 변수에 두 스레드가 동시에 접근한다면, 에러가 발생한다. +1이 되는 버튼을 두 스레드가 동시에 누른다면 해당 작업은 처리되지 않는다. 이 문제점은 나중에 불변 객체, 순수 함수의 필요성으로 이어진다.
기본적으로 비동기 작업이란, 시간이 오래걸리는 작업을 다른 선로에 놓아주는 것을 말한다. 하나의 기찻길에서 가장 앞에서 달리는 기차가 지연된다면, 그 뒤의 기차들도 갈 길을 가지 못하고 줄줄이 지연된다. 이런 상황을 방지하기 위해 지연되는 기차를 다른 선로로 옮겨 작업을 진행하고, 작업이 완료되면 다시 콜백해주는 것이 기본적인 비동기의 개념이다.
여기서 선로는 지금까지 위에서 알아본 스레드를 의미한다. 그런데 자바스크립트 엔진은 싱!글! 스레드이다.
싱글 스레드인 자바스크립트가 어떻게 비동기 작업을 위한 스레드를 하나 더 마련할 수 있는걸까?
정답은 Web API 덕분! 브라우저나 NodeJS가 운영한다. 이들이 제공하는 기능엔 AJAX, setTimeout(), addEventListner()등등이 있다.
자바스크립트는 싱글 스레드를 가지고 있고 그곳에서 task들을 처리하지만, 비동기 작업으로 진행해야 하는 경우 Web API의 비동기 처리용 스레드로 보낸다.
여기서 작업들이 비동기적으로 처리가 완료되면 콜백들을 자바스크립트의 태스크 큐(Task Que)로 보내고, 이벤트루프가 이것들을 자바스크립트의 콜 스택(Call Stack)으로 옮겨오는 것이다.
때문에 자바스크립트 엔진은 싱글 스레드이지만 비동기적 처리가 가능한 것이다.
큐?
큐는 한쪽 끝에서는 삽입, 반대쪽 끝에서는 삭제 작업이 이루어지는 First In First Out 형식의 자료구조이다. 꺼내는 쪽에서 가장 가까운 데이터를 Front라고 하고 넣는 쪽에서 가장 가까운 데이터를 Rear라고 한다. 데이터를 차례대로 넣는 연산과 처음 저장된 데이터부터 하나씩 꺼내는 연산 두 종류가 있다.
위에서 설명한 것과 같이 비동기 작업을 Web API의 스레드에서 처리한 후 태스크큐와 이벤트루프를 거쳐 그 콜백을 자바스크립트의 콜 스택에 쌓아 처리한다. 이걸 코드로 옮겨 그냥 비동기 로직을 코딩하면 콜백 지옥에 빠지기 쉽다. 콜백 지옥은 가독성도 안 좋게 하고 실수도 유발해 지양해야 한다.
콜백 지옥을 피하고, 복잡한 비동기 로직을 직관적이고 보다 쉽게 작성하기 위해 자바스크립트 문법에 여러 발전이 있었는데 그게 바로 Promise와 async-await이다!
정리 잘해두셨네요 !! 학습하고 갑니다 ㅎㅎ