자바스크립트는 싱글 쓰레드라며?

Nochi·2023년 2월 24일
1

읽기만 해도 돼

목록 보기
2/3

멘토링을 신청하기 전에 상담을 받았는데 내용에 대해서 자세히 알아야 할 것 같아서 정리하게 되었다.
나의 글은 나를 위한 정리용이어서 노마드 코더(EP 09.) 논블로킹 언어가 뭐야? | 자바스크립트 개발자라면 알아야하는 핵심 컨셉 33개을 보는 것을 추천한다.

싱글 쓰레드라며?

자바스크립트의 메인 쓰레드는 싱글 스레드이지만 일반적으로 다른 객체가 일을 하든 말든 상관 안하는 논블로킹 I/O를 사용한다. 이벤트 루프콜백 함수를 이용하여 논블로킹 I/O를 구현하였다.

어떻게 이 언어가 멀티 스레드처럼 동작하는지 간단하게 설명해보고자 한다.

위 이미지는 비동기 함수가 어떻게 동작하는지 구조를 설명해주고 있다.
차근차근 알아보자.

JS Engine

JavaScript 엔진은 자바스크립트 코드를 실행하기 위한 프로그램이다. 자바스크립트 코드를 실행하기 위한 프로그램의 메모리 구조는 아래와 같다.

  • 힙(Heap) : 객체, 배열 등의 동적으로 생성되는 데이터가 저장되는 공간. 힙은 크기가 동적으로 변할 수 있으며, 메모리 할당과 해제가 이루어진다.

  • 스택(Stack) : 실행 컨텍스트(Execution Context)가 저장되는 공간. 실행 컨텍스트는 함수가 호출될 때마다 생성되며, 함수가 실행되는 동안에는 해당 실행 컨텍스트가 스택에 저장된다. 함수가 실행을 마치면 해당 실행 컨텍스트는 스택에서 제거된다.

  • 데이터 세그먼트(Data Segment) : 정적인 데이터와 코드가 저장되는 공간. 예를 들어, 전역 변수, 상수, 문자열 등이 저장된다.

Call Stack에서 Stack(LIFO) 방식으로 실행 컨텍스트가 쌓이며 진행된다. 진행하게 되면서 동기 함수들은 그대로 실행하게 되고 비동기 함수들은 Web API로 처리하게 되며 일을 분배한다.

함수 (MDN web Docs)

자바스크립트에서 함수는 객체(Object)의 일종이며, 함수 객체(Function Object)라고 부릅니다. 함수 객체는 참조 타입 데이터로 힙 메모리에 할당되며, 해당 함수의 코드와 함께 함수의 프로퍼티와 메소드도 포함됩니다.

Web API

Web API (MDN web Docs)

웹 API란 개발자가 브라우저 상에 쉽게 개발할 수 있도록 도와주는 객체 모음들.

  • Call Stack에서 비동기 함수 실행 컨텍스트가 호출되면, 비동기 함수 실행 컨텍스트는 호출 스택에서 제거 된다.
  • 이벤트 루프는 Web API에서 제거된 해당 비동기 함수 컨텍스트를 처리하도록 지시한다.
  • Web API는 비동기 함수를 백그라운드에서 비동기적으로 처리한다.
  • 처리가 끝난 후, 해당 콜백 함수를 Callback Queue에 넣는다.

비동기 함수와 콜백 함수

setTimeout(() => {
  console.log("Delayed for 1 second.");
}, 1000)

문득 콜백 함수가 무엇인지 궁금해 할 수 있을 것 같아서 준비했다.
setTimeout()은 비동기 함수이고 ()=>{ 실행 코드 } 가 콜백 함수이다.
비동기 함수의 실행이 끝나면 콜백 함수가 Callback Queue에 넣어지는 것이다.

Callback Queue(Task Queue)

: 이벤트 루프(event loop)에서 사용되는 공간. 큐는 비동기적인 작업이 완료되었을 때, 이벤트 루프에 의해 호출 스택으로 넘겨질 콜백 함수들을 저장하는 공간.

  • Event Loop에서 비동기 함수를 꺼내기 전까지 Queue(FIFO) 방식으로 보관한다.

Event Loop

  • 이벤트 루프는 자바스크립트의 메인 스레드 동작 타이밍을 관리하는 관리자이다.

: Event Loop는 Call Stack과 Callback Quque 상태를 계속 감시하며 Call Stack 에 함수들이 존재하지 않는다면 Callback Queue에 있는 처리가 완료된 비동기 함수들의 콜백 함수들을 Call Stack에 밀어넣게 된다. 그 후 Call Stack에서 비동기 함수를 실행시키게 된다.

짧게 말하면, Call Stack이 비어있으면 Callback Queue에 있는 콜백 함수들을 밀어넣는 역할.


정리

자바스크립트는 기본적으로 단일 스레드(single-threaded) 언어이며, 일반적으로 논블로킹(non-blocking) I/O를 사용한다. 논블로킹 I/O를 위해 이벤트 루프(event loop)콜백 함수(callback function)을 이용한다.

논블로킹 I/O는 비동기적으로 작업을 처리하는 방식으로, 작업을 수행하는 동안 다른 작업도 처리할 수 있도록 한다. 자바스크립트는 비동기적인 작업을 수행하기 위해 콜백 함수를 사용한다.

이벤트 루프는 비동기적인 작업을 처리하고, 작업이 완료될 때까지 다른 작업을 처리할 수 있도록 한다. 이벤트 루프는 브라우저나 Node.js와 같은 환경에서 구현되어 있으며, 작업을 처리하는 동안 콜백 함수를 호출하여 결과를 반환한다.

자바스크립트는 기본적으로 논블로킹 I/O를 사용하며, 이벤트 루프와 콜백 함수를 이용하여 비동기적인 작업을 처리합니다. 이를 통해 자바스크립트는 블로킹 작업이 발생하더라도 전체 애플리케이션이 차단되는 문제를 해결하고, 높은 성능과 사용자 경험을 제공할 수 있습니다.


후기

이 글을 완성하게 되는데 3일 쯤 걸린 것 같다. 3일을 몰두한 것은 아니다.
3일 동안 적은 내용이 왜이렇게 짧냐 할 수 있지만, 내용을 알게 될수록 처음 적었던 내용보다 더 줄어들고 정리가 되었다.

해당 내용의 전체적인 흐름을 이해하는 것은 어렵진 않았지만, 글을 찾아다니면서 찝찝했던 문제들이 여럿 남아있었다.
그 중 하나는 "함수가 객체여서 힙 메모리에 저장되는데 어떻게 콜 스택에 쌓인다는 걸까?"라는 고민이었다. 함수가 쌓인다는 개념이 아니라 실행 컨텍스트가 쌓인다는 개념을 이해하게 되면서 해당 고민을 해결하게 되었다.
두번째는 "웹 API에서 비동기 함수를 반환한다"라는 표현이었다. 그래서 setTimeout 함수 통째로 오는건가 싶은 의문가 그 해답을 찾기 위해서 찾아다녔다. 그래서 찾은 정답으로 이해가 쉬울 수 있게 '처리가 완료된 비동기 함수들의 콜백 함수'표현으로 정리하였다.

아직도 해결되지 않는 의문들이 있다. 예시를 들면 "Web API는 객체들의 모음인데, 비동기 처리를 하는 객체는 무엇일까?"라는 내용인데 계속 들어가다보면 완성되지 않을 것 같아서 이만큼만 정리하려고 한다.


부가 설명

웹 브라우저

일반적으로 웹 브라우저는 멀티 스레드입니다.

웹 브라우저는 동시에 여러 가지 작업을 수행해야 하기 때문에, 멀티 스레드를 사용하여 여러 작업을 동시에 처리합니다. 이러한 작업에는 웹 페이지의 로딩, 자바스크립트 코드 실행, 렌더링 및 사용자 입력 처리 등이 있습니다.

또한, 모던 웹 브라우저는 렌더링 엔진, 자바스크립트 엔진, 네트워크 엔진, UI 엔진 등 다양한 구성 요소를 가지고 있습니다. 이러한 구성 요소는 각각 독립적인 스레드로 작동할 수 있으며, 이는 브라우저의 성능을 향상시키는 데 도움이 됩니다.

따라서, 대부분의 웹 브라우저는 멀티 스레드를 사용하여 다양한 작업을 동시에 처리합니다.

Node.js

Node.js는 기본적으로 싱글 스레드입니다. 이것은 Node.js 자체의 런타임이 싱글 스레드로 작동한다는 것을 의미합니다.

그러나 Node.js는 이벤트 기반(Event-driven)과 비동기 I/O 처리(Asynchronous I/O)를 통해 비동기적으로 작업을 처리할 수 있습니다. 이를 통해 Node.js는 많은 작업을 처리하면서도 블로킹되는 것을 방지할 수 있으며, 이러한 특성이 Node.js를 다중 스레드 애플리케이션과 비교해 더 나은 확장성과 성능을 제공할 수 있습니다.

또한, Node.js는 Worker Threads 모듈을 사용하여 멀티 스레드를 지원합니다. Worker Threads 모듈은 Node.js에서 작동하는 멀티 스레드를 구현할 수 있는 기능을 제공합니다. 따라서, Node.js에서 멀티 스레드를 사용할 수 있지만, 기본적으로는 싱글 스레드 모델을 사용하므로 이를 고려하여 설계해야 합니다.

[참고]

0개의 댓글