이전에 한 번 딜레마를 겪었던 주제 "비동기" !!!!
비동기 함수인 async-await에 대해서 처음 학습하고 나서 자바스크립트의 비동기를 검색했다가 자바스크립트 엔진에 대한 이야기로 빠져서 '이걸 공부하려고 한 건 아닌데... 근데 연관되는 거 같긴 해... 근데 어렵네...😶🌫️' 여러 가지 생각을 하며 일단 학습했던 기억이 있다.
지금은 어느정도 각각에 대한 이론을 알고 있다고 생각하지만, 이를 말로 표현하려고 하니까 여전히 말문이 막힌다.
말문을 강제로 트이게(?)하기 위해 포스팅을 통해 정리해 본다.
비동기 (Asynchronous)
둘 이상의 객체 또는 이벤트가 동시에 존재하지 않거나 발생하지 않는 경우(또는 이전 객체 또는 이벤트가 완료될 때까지 기다리지 않고 발생하는 여러 관련 작업)를 말합니다.
- MDN : 비동기(Asynchronous)
비동기란?
어떤 작업을 수행할 때, 그 작업이 완료될 때까지 기다리지 않고 다른 작업을 동시에 수행할 수 있는 방식을 의미한다.
프로그래밍에서의 비동기는 여러 작업이 동시에 실행될 때 서로 간섭하지 않고 독립적으로 실행할 수 있도록 설계된 방법이다.
동기 (Synchronous)
그렇다면 동기는?
한 번에 하나씩 작업을 처리하는 방식을 의미하며, 비동기의 반대 개념이다.
동기 (Synchronous) | 비동기 (Asynchronous) |
하나의 작업이 끝나야만 다음 작업이 실행 |
하나의 작업이 실행되는 동안 다른 작업을 함께 수행 |
카페에서 줄 선 순서대로 주문한다. 주문 후 음료까지 받고 나서야, 다음 사람이 주문한다. |
카페에서 줄 선 순서대로 주문한다. 주문 후 음료를 기다릴 동안, 다음 사람은 계속해서 주문한다. |
병렬 (Parallel)
언젠가 비동기 처리에 대해 내가 정리했던 문구는 다음과 같다.
비동기는 특정코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는,
병렬적인 실행을 하는 자바스크립트의 특성을 의미합니다.
여기서 사용된 병렬이란 여러 작업이 정확히 동시에 실행된다는 것을 의미한다.
병렬 처리는 멀티 스레드를 활용하여 여러 작업이 물리적으로 동시에 실행되는 것을 말한다. 예를 들어 멀티코어 CPU가 있을 때, 각 코어가 독립적으로 다른 작업을 동시에 수행한다.
그런데 비동기는?
일단 자바스크립트는 한 번에 하나의 작업문 실행할 수 있는 싱글 스레드 언어이다. 자바스크립트에서의 비동기 처리는 이벤트 루프를 활용하여 각 작업의 실행 순서를 효율적으로 조정하는 것(하나의 작업이 진행되는 동안 대기 중인 다른 작업을 순차적으로 실행될 수 있도록 관리)을 말한다. 마치 여러 작업이 겹쳐서 실행되는 것처럼 보이게 하는 것일 뿐 실제로 동시에 실행하는 것은 아니다.
(관련된 내용은 아래에서 조금 더 자세히 다룬다)
정리하자면 비동기와 병렬은 개념적으로 완전히 다른 실행 방식이기 때문에 위처럼 설명하는 것은 혼동을 초래할 수 있다.
비동기를 이해하는 데에 있어 병렬 키워드를 사용하는 것은 지양하는 것이 좋을 것 같아 먼저 설명해보았다.
자바스크립트의 비동기 동작
비동기 작업을 수행하는 자바스크립트에 대해서 내용을 정리해 보자.
싱글 스레드 프로그래밍 언어, JavaScript
스레드(thread)란 한 프로세스 안에서 다양한 작업을 담당하는 최소 실행 단위이다. 각각의 스레드는 독립적인 작업을 수행하며, 고유한 스레드 ID와 프로그램 카운터 등을 갖고 있다.
싱글 스레드는 하나의 프로세스에서 하나의 스레드만 실행하는 방식으로, 단순한 작업이나 순차적인 작업 처리에 유리하다.
반면 멀티 스레드는 스레드 간의 자원을 공유하여 하나의 프로세스에서 다수의 스레드를 실행하는 형태이다. 복잡한 작업이나 동시성이 중요한 작업 처리에 효율적이다.
JavaScript는 싱글 스레드 프로그래밍 언어이다.
웹 페이지 구현에 사용하던 JAVA는 멀티 스레드 프로그래밍 언어인데, 이것이 다소 무겁고 어렵다고 생각해 도입한 경량 프로그래밍 언어가 JavaScript이기에 싱글 스레드 프로그래밍 언어로 탄생하게 됐다고 이해하면 된다.
즉, JavaScript는 한 번에 하나의 작업만 수행할 수 있으며, 이전 작업이 완료되어야 다음 작업을 수행할 수 있다.
코드가 위에서 아래로 차례로 동작하는 방식이 이것과 관련이 있으며, 이런 코드 순차 실행을 동기라 부른다.
동기는 불편해... 비동기는 어때?
이런 동기적 수행 방식은 단점을 갖는다.
예를 들어 웹 애플리케이션에서 데이터베이스 쿼리를 수행해야 한다고 가정한다면, 데이터베이스 응답이 올 때까지 다른 요청은 전혀 처리하지 못하고 기다려야만 한다. 만일 대규모 트래픽이 발생한 경우, 처리가 블로킹되어 성능 저하가 발생할 수 있다.
그럼 만일 위 예시에서 비동기 수행을 한다면?
데이터베이스 응답이 올 때까지 마냥 기다리지 않고 다른 요청을 처리할 수 있게 된다. 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있어 자원을 효율적으로 사용할 수 있다. 대규모 트래픽이 발생해도 안정적으로 동작하는 웹 애플리케이션을 만들 수 있다.
이러한 수요로 JavaScript에는 여러 작업을 동시에 처리하기 위한 비동기라는 개념을 도입하게 된다.
비동기는 어떻게? Web APIs와 이벤트 루프를 통해
앞서 JavaScript는 싱글 스레드 언어라고 말했다. 여기에서 싱글 스레드 방식으로 동작하는 것은 웹 브라우저에 내장된 자바스크립트 엔진을 말한다. 엔진을 통해서 JavaScript 자체가 동기적으로 일을 처리하는 것이다.
그런데 런타임인 웹 브라우저가 제공하는 Web APIs는 멀티 스레드를 사용한다.
이 Web APIs를 통해서 자바스크립트의 비동기 동작을 구현한다.
갑자기 뭔가 어지럽네? 🧐 과정에 대해 하나하나 세부적으로 알아보자.
싱글 스레드로 동작하는 자바스크립트 엔진
JavaScript 코드를 실행하는 프로그램 또는 인터프리터(해석기)를 자바스크립트 엔진이라고 말한다.
이렇게 엔진에 의한 인터프리팅 방식은 별도의 컴파일 과정을 필요로 하지 않는다. 즉, 코드가 웹 브라우저에서 즉시 해석되어 실행한다.
자바스크립트 엔진의 가장 대표적인 예시로 Google의 V8이 있다. V8은 웹어셈블리(WebAssembly) 엔진으로, JavaScript를 바이트 코드로 컴파일하고 실행하며, JavaScript를 보완하고 있다. Chrome과 Node.js 등에서 사용되고 있다.
V8 안에는 Call Stack과 Memory Heap이 존재하며, 이 둘을 통해서 데이터 및 코드 실행을 관리한다.
- 호출 스택(Call Stack): 코드 실행에 따라 호출 스택이 쌓이는 곳. 코드를 읽고 함수가 실행되는 순서를 기억한다.
- 메모리 힙(Memory Heap): 변수와 객체의 메모리 할당에 사용되는 비정형 메모리
V8은 하나의 Call Stack을 가지기에, 즉 한 번에 한 가지 일만 진행하는 동기 방식으로 실행된다.
멀티 스레드로 동작하는 Web APIs
자바스크립트 런타임(run-time)은 JavaScript가 실행될 수 있는 다양한 환경을 말하며, 웹 브라우저와 Node.js 등이 이에 해당된다. 이 런타임 모델의 구성요소를 살펴보면 다음과 같이 정리할 수 있다.
- 자바스크립트 엔진 (Memory Heap과 Call Stack)
- Web APIs: 타이머, 네트워크 요청, 파일 입출력, 이벤트 처리 등 브라우저에 제공하는 다양한 API들 (ex. setTimeout, XMLHttpRequest, File API, DOM Event 등)
- 이벤트 루프: 자바스크립트의 비동기 동작을 관리하는 핵심 메커니즘 중 하나. 비동기 함수를 호출하고 해당 작업이 완료될 때까지 대기하지 않고 Callback Queue에 담는다. 비동기 작업이 완료되면 콜백 함수를 Call Stack에 넣어 실행될 수 있도록 관리한다.
이 중에서 Web APIs에 주목해본다.
Web APIs는 각 API마다 스레드들이 할당되어 있으며, 이들이 모여 멀티 스레드를 이룬다.
즉, Web APIs는 멀티 스레드이기 때문에 동시 작업 처리가 가능하며 비동기 작업을 수행할 수 있다고 정리할 수 있다.
이런 API들이 자바스크립트의 주 스레드 외부에서 실행되며, 비동기 작업을 처리한다.
자바스크립트의 비동기 처리
추후 작성 예정... 보완중 ⚒️
참고
[JavaScript] 런타임 작동 방식, 비동기와 이벤트 루프
'JAVASCRIPT' 카테고리의 다른 글
[JAVASCRIPT] 코딩테스트에서 만나는 DFS와 BFS (feat. 큐) (1) | 2024.10.14 |
---|---|
[JAVASCRIPT][PCCP 대비] 프로그래머스 레벨1, 2 빠르게 풀고 메모하기 (0) | 2024.05.08 |
[JAVASCRIPT] Execution Context : 실행 컨텍스트 - 콜스택 / 렉시컬 환경 / 호이스팅 / 스코프 체인 (0) | 2024.01.28 |
[JAVASCRIPT] var로 알아보는 변수 선언과 할당 - 실행 컨텍스트 / 변수 호이스팅 / TDZ / 가비지 컬렉터 (1) | 2024.01.06 |
[JAVASCRIPT] Callback Function : 콜백 함수 - 타이머 함수 / 비동기 / Promise / async - await (0) | 2023.08.27 |