안녕하세요 오늘의 포스팅은 자바스크립트는 정말 싱글스레드로 동작하는가?에 대해서 포스팅하겠습니다.

자바스크립트로 개발을 하던중 자바스크립트는 비동기 함수 or Promise.all등의 문법으로 라이브러리나 패키지가 아닌 언어수준에서 병렬처리가 가능한대 어떻게 싱글스레드 언어로 분류되는지에 대한 의문이 생겨 오늘의 포스팅을 작성하게 되었습니다.

자바스크립트는 싱글스레드 언어라고 알려져있는데 어떻게 언어수준에서 병렬처리를 제공하는지에 대해 알아보겠습니다.

먼저 기반지식으로 이벤트루프란 무엇인지에 대해 알아보겠습니다.

 

 

 

이벤트 루프란?

  • 자바스크립트 엔진이 아닌, 런타임(browser, node.js)에서 가지고 있는 하나의 장치입니다.
  • 콜 스택과 태스크 큐(콜백 큐)를 감시하며, 콜 스택이 비어있는 경우에 태스크 큐에서 태스크를 가져와 콜 스택에 넣어 주는 동작을 합니다.
  • → 자바스크립트는 싱글스레드 언어이기 때문에 한번에 하나씩 실행되지만, Web API, Callback Queue, Event Loop 로 인하여 멀티스레드처럼 보입니다.
  • 태스크가 들어오길 기다렸다가 태스크가 들어오면 이를 처리하고, 처리할 태스크가 없는 경우에는 대기하는 형태입니다.

 

 

이벤트 루프는 큐의 다음 메시지를 처리한다는 의미이다.

  • 이벤트 루프는 그 구현 방식 때문에 붙은 이름으로 아래와 동작과정이 유사하다.
while(queue.waitForMessage()){
  queue.processNextMessage();
}
  • queue.waitForMessage() 함수는 현재 아무 메시지도 없다면 새로운 메시지 도착을 동기적으로 기다림.

 

  • 이벤트 루프가 동작하려면 2가지 조건이 충족되어야 합니다.
  • 아래의 두 조건이 충족될 때 Callback Queue 에 있는 함수들을 순서대로 Call Stack 으로 이동시켜 해당 함수가 호출되도록 함. 
    • Callback Queue 에 실행해야 할 함수가 있다.
    • Call Stack 이 비어있다.

 

 

 

 

자바스크립트는 현재 위치한 곳의 함수들의 호출이 끝나야만 다음 작업을 실행한다.
  • 예를 들어, setTimeout 에 3초의 시간을 두고 함수를 실행하고자 할 때 3초 후 Callback Queue 로 넘어가긴 하겠지만, 그 사이 Call Stack 이 비어지지 않는다면 Event Loop 는 동작하지 않을 것입니다.
  • → 즉, setTimeout 으로 걸어둔 함수가 반드시 3초 후에 실행될거라는 보장이 없다는 뜻이기도 합니다.
  • 나아가 Event LoopCallback Queue 뿐 아니라 render queue, job queue 등 여러가지 큐를 관리하고 실행하기 때문에 유념해야할 점은 내가 원하는 정확한 시점에 정확히 Event Loop 가 동작하여 함수를 실행하지 않을수도 있다는 것 입니다.

 

 

자바스크립트가 싱글 스레드인 이유는 콜 스택이 하나이기 때문이다.

  • 자바스크립트는 콜 스택이라는 자료 구조를 이용해서 명령문을 실행하는데, 하나의 스레드에서 하나의 콜 스택으로 모든 명령문을 순차적으로 실행하기 때문에 싱글스레드 언어라고 할 수 있습니다.
  • → 이 말은 즉, 한 번에 하나의 태스크(작업)만 처리가 가능하다는 뜻임. (하나의 함수가 실행되면 이 함수의 실행이 끝날 때까지 어떤 작업도 중간에 끼어들지 못함)
  • 브라우저는 탭마다 하나의 스레드를 생성하며, 프로그램은 이 메인 스레드(싱글 스레드)에서 작동함.그렇기 때문에 이벤트 루프가 동작하는 스레드가 메인 스레드라고 볼 수 있습니다.
  • → 자바스크립트를 실행시키는 스레드는 단 하나뿐이며, 이 스레드가 바로 이벤트 루프가 실행되는 스레드입니다.

 

js 런타임(browser, node.js)의 구조를 도식화한 그림

 

자바스크립트 런타임이란?

  • 프로그래밍 언어가 구동되는 환경으로, 쉽게 말해 프로그램을 뜻합니다. → 즉, 런타임이란 “어떤 프로그래밍 언어가 동작할 수 있는 프로그램"입니다.
  • 자바스크립트의 런타임은 무엇이 있을까? Browser or Node.js 가 대표적인 자바스크립트 런타임입니다.

 

 

자바스크립트는 정말 싱글 스레드일까?

  • 자바스크립트 엔진만 보면 싱글 스레드가 맞지만, 런타임으로 확장해서 보면 멀티 스레드라고 할 수 있습니다.
  • 브라우저 엔진은 렌더링, 통신 준비, 메모리 초기화, 프로세스 정리 등과 같은 수많은 작업을 백그라운드에서 멀티스레드로 처리합니다.
  • 자바스크립트 엔진은 콜 스택과 메모리 힙만 담당하고 나머지는 브라우저 영역에서 담당합니다.→ 이처럼 실제로 자바스크립트 엔진은 독립적으로 실행되지 않고, 런타임(웹 Browser or NodeJS같은) 멀티 스레드 환경에 임베디드되어 실행됩니다.
  • 즉, 런타임 영역에서 구동됩니다.

핵심!!!!!!!

→ 결과적으로 자바스크립트 자체는 싱글스레드가 맞지만, 현실적으로 자바스크립트 엔진이 독립적으로 실행되지 않기 때문에 자바스크립트와 Web API, 이벤트 루프 등의 런타임 환경(멀티스레드로 동작)을 분리하여 말하기가 어렵습니다.

 

 

자바스크립트 비동기 동작의 핵심 요소는 런타임(Browser, node.js) 가지고 있다.

아래의 그림을 한번 더 소환하겠다!!!

js 런타임(browser, node.js)의 구조를 도식화한 그림

  • 자바스크립트는 싱글스레드이지만, 이벤트 루프를 통한 비동기 방식으로 동시성을 지원합니다.
  • Web API, Event Table, Callback Queue, Event Loop 덕분에 자바스크립트를 멀티 스레드처럼 작동시킬 수 있습니다.
  • 비동기 호출을 위해 사용되는 setTimeout, XMLHttpRequest 와 같은 함수들은 Web API 에 정의되어 있습니다.
  • → 당장 실행되지 않는 함수들이 호출되기를 기다리는 공간이라고 볼 수 있으며, 해당 함수가 콜 스택에서 Web API 로 이동될 때 Call Stack 에서는 호출이 끝난 것으로 간주되어 사라지게 됩니다. (정해진 시간이 지나면 함수 호출을 위해 Callback Queue 로 이동함)
  • Nods.js는 비동기 지원을 위해 libuv라이브러리를 사용하며, 이 linuv 가 이벤트 루프를 제공함. → 자바스크립트 엔진은 비동기 작업을 위해 노드js의 api를 호출하며, 이 때 넘겨진 콜백은 libuv의 이벤트 루프를 통해 스케쥴되고 실행됨. (단, 자바스크립트 엔진의 이벤트 루프와는 다르게 동작함)

node.js의 구조

 

 

 

비동기 함수 동작 원리

1. 인터프리터가 비동기 함수를 만나면, 즉시 Call Stack에서 지워버린다.
2. 이 비동기 함수는 Web API로 넘어간다.

3. 비동기 함수는 Web API에 담겨있다가, 타이머나 로드 등이 완료되면 Callback Queue로 보내진다.

4. Event LoopCall StackCallback Queue 사이에서 Call Stack이 비어있는지 주시한다.

5. 모든 함수의 실행이 완료되고 Call Stack이 비워지면, Event LoopCallback Queue에 담겨있는 함수들을 먼저 들어온 순서대로 Call Stack으로 넘겨준다.

 

 

정리

위의 내용을 주제로 42seoul에서 js스터디를 할 당시(11개월전) 10시에 만나서 16시에 스터디가 마무리된 기억이 있다.

그 때 당시에 이해는 했지만 시간이 흐른뒤 무뎌진 지식을 다시 블로그글로 정리를 하려니 생략한 내용도 많지만 어쨋든 정리를 완료했다!!!

 

js를 공부한지 얼마 안되었거나 깊게 학습하지 않아 동작원리까지 학습되지 않은 분들이 해당 포스팅을 통해 최소 js는 싱글스레드 언어이지만 어떻게 async문법 or Promise.all 문법을 사용하여 병렬처리가 가능한지 대략은 이해가 되었으면 좋겠다.

 

js시리즈 다음글은 테스크 큐에서의 우선순위에 대한 글이 될 예정이다.

 

반응형

'javascript' 카테고리의 다른 글

[js] 비동기 함수 에러 핸들링  (0) 2022.10.02
[js] 콜백 큐의 종류에 따른 우선순위!  (0) 2022.07.10

+ Recent posts