자바스크립트는 왜 싱글 스레드(Single thread)일까?

이동준·2023년 7월 30일
0

자바스크립트

목록 보기
22/28

싱글 스레드의 특징

  • 한번에 하나의 일만 수행 가능
  • 문맥 교환(context switching)이 필요하지 않음
  • 프로그래밍 난이도가 쉽고, CPU 및 메모리 사용이 적음
  • 단순 CPU만을 사용하는 계산 작업은 오히려 멀티 스레드보다 효율적일 수 있음
  • 연산량이 많은 작업을 할 경우 그 작업이 완료되어야 다른 작업을 할 수 있어 멀티 스레드에 비해 효율이 급격히 떨어짐
  • 에러 처리를 못 할 경우 동작을 멈춤

문맥 교환이란?
현재까지의 작업 상태나 다음 작업에 필요한 각종 데이터를 저장하고 읽어오는 작업
하나의 프로세스가 CPU를 사용중인 상태에서 다른 프로세스가 CPU를 사용하도록 하기 위해, 이 전의 프로세스의 상태를 보관하고 새로운 프로세스의 상태를 적재하는 작업

자바스크립트는 싱글 스레드 언어라고 알려져있다. 그러나 보통 싱글 스레드라고 하면 한번에 하나의 작업만 수행할 수 있다고 알고 있는데, 자바스크립트는 어떻게 한번에 여러 요청을 받을 수 있을까?

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

결론부터 말하자면 싱글 스레드가 맞다. 자바스크립트의 메인 스레드인 이벤트 루프가 싱글 스레드이기 때문에 자바스크립트는 싱글 스레드 언어라고 부른다. 하지만 이벤트 루프만 독립적으로 실행되지 않고 웹 브라우저나 NodeJs와 같은 멀티 스레드 환경에서 실행된다. 즉, 자바스크립트 자체는 싱글 스레드가 맞지만, 자바스크립트 런타임은 싱글 스레드가 아니라고 할 수 있다.

자바스크립트는 왜 싱글 스레드를 선택했을까?

자바스크립트는 원래 웹페이지의 보조적인 기능을 수행하려고 만들어진 언어이다. 멀티 스레드인 자바는 다소 무겁고 어렵다는 인식이 있고, 동시성 문제가 존재하다보니, 복잡한 시나리오를 신경 쓸 필요가 없는 싱글 스레드 형식이 채택되었었다.
실제로 구글 Chrome 브라우저는 기존 웹 페이지에서 동시성 문제를 일으킬 수 있다는 이유로 단일 웹 사이트 페이지의 자바스크립트 코드가 동시에 실행되는 것을 허용하지 않는다.

기존 동기식 요청은 코드 한줄씩 차례대로 실행했다. 그래서 하나의 작업에 걸리는 시간에 관계없이 첫번째 코드가 실행된 뒤 다음 코드가 실행됐다. 이렇게 되면 앞의 작업시간이 길수록 시간의 낭비가 심해진다. 이러한 문제는 하나의 요청이 완료될 때까지 기다리지 않고 동시에 다른 작업을 실행하는 비동기 호출로 극복할 수 있다.

자바스크립트 비동기 런타임 과정

자바스크립트가 비동기 코드를 어떻게 동작시키는지 알아보기 위해선 자바스크립트의 런타임 환경에 대해 알아야 한다. 자바스크립트가 실행될 때는 다음과 같은 요소들이 실행을 도와준다.

  • Call Stack : 자바스크립트에서 수행해야 할 함수들을 순차적으로 스텍에 담아 처리
  • Web API : 웹 브라우저에서 제공하는 API로 AJAX나 Timeout등 비동기 작업을 실행
  • Task Queue : Callback Queue라고도 하며 Web API에서 넘겨받은 Callback 함수를 저장
  • Event Loop : Call Stack이 비어있다면 Task Queue의 작업을 Call Stack으로 옮김

실제 비동기 코드는 이런 식으로 앞선 설명처럼 이렇게 동작하게 된다.

console.log("처음 실행");
setTimeout(() => console.log("두번째 실행?"), 0);
console.log("세번째 실행?");

// 처음 실행
// 세번째 실행?
// 두번째 실행?

문자열이 출력된 순서를 보면 코드의 입력 순서와는 다르게 setTimeout() 안의 콘솔문의 출력이 마지막에 이루어진다.

  1. 맨 처음에 console.log("처음 실행"); 가 콜 스텍에 쌓이게 되고, 바로 실행되어 콜 스텍에서 제거된다.
  2. 그 후 setTimeout(() => console.log("두번째 실행?"), 0); 이 콜 스텍에 쌓이게 되고, setTimeout() 과 같은 비동기 작업은 바로 실행되지 않고 콜 스텍에서 Web API로 넘어가게 되어 비동기 처리가 된 후 콜백 함수를 테스크 큐로 넘겨 순서를 기다린다.
  3. console.log("세번째 실행?"); 가 콜 스텍에 쌓이게 되고, 바로 실행되어 콜 스텍에서 제거된다.
  4. 이벤트 루프가 콜 스텍에 스텍이 없는 것을 확인하면, 테스크 큐에 있는 setTimeout() 의 콜백 함수를 콜 스텍에 호출한다.
  5. 콜 스텍에 불러온 콜백 함수를 실행시키고 콜 스텍에서 제거된다.

0개의 댓글