본문 바로가기
Programming/4. JavaScript & React

009_자바스크립트, 싱글 쓰레드, 비동기, 논블로킹, 이벤트 루프

by @sangseophwang 2022. 3. 14.

자바스크립트는 싱글 쓰레드 언어인데 비동기 처리가 가능하다?

글을 시작하기 전 알아둬야 할 지식

1. 프로그램 (Program)
- 어떤 작업을 위해 실행할 수 있는 파일. 
- 정적인 개념 (아직 동작하지 않고 있기 때문)

2. 프로세스 (Process)
- 프로그램이 메모리에 올라와 cpu(자원)를 할당받고 프로그램이 실행되고 있는 상태.
- 여기서 자원은 cpu 시간, 운영되기 위해 필요한 주소 공간, Code, Data, Stack, Heap 구조로 되어 있는 독립된 메모리 영역을 말한다.
- 기본적으로 프로세스당 최소 1개의 쓰레드(메인 쓰레드)를 가진다.
- 동적인 개념 (프로그램이 동작하고 있기 때문)

3. 쓰레드 (Thread)
- 프로세스 내에서 실행되는 흐름의 단위
- 쓰레드가 1개면 싱글 쓰레드, 2개 이상이면 멀티 쓰레드라고 한다.
- 쓰레드는 프로세스의 Code, Data, Heap을 공유하며 Stack은 개별적으로 할당받는다. 
- 공용 회의실의 모니터, 스피커, 리모콘을 공용 자원의 느낌으로 보면 될 것 같다.

4. 동기 (Synchronous)
- 현재 실행중인 코드가 끝나야 다음 코드를 실행
- 들어온 순서대로 처리하며, 실행 순서가 보장되지만 현재 task가 처리되지 않으면 넘어갈 수 없다.

5. 비동기 (Asynchronous)
- 동기의 반대 개념.
- 현재 코드가 끝나지 않아도 기다리지 않고 다음 코드를 실행한다.
- 대신 task의 실행 순서 보장이 되지 않는다.

 

 프론트엔드 공부를 하면서 아마 종종 들었을 것이다. '자바스크립트는 싱글 쓰레드 언어이다.' 보통 싱글 쓰레드라고 하면 일을 처리하는 단위가 하나니까 한 번에 하나의 작업만 수행할텐데, 우리가 여러 웹사이트를 접해봐서 알겠지만 동시에 여러 요청을 받고 수행하는 것을 보면 어떻게 싱글 쓰레드로 가능한지 궁금할 것이다. 오늘 이에 대해 가볍지만 핵심만 쏙쏙 다뤄보고자 한다.

다들 궁금해하는 이 주제! 지금 시작합니다!

 

Q_1.  싱글 쓰레드?

- 우선 싱글 쓰레드이면 어떤 식으로 작업을 수행하는지 이해할 필요가 있다.
- 쉽게 생각해 어떤 공장에 사람이 하나뿐이고 모든 제품이 이 사람을 통해서 만들어져야 한다고 이해하면 좋을 것 같다.
- 한 제품(task)이 다 만들어지기 전까지는 그 다음 제품의 작업은 수행할 수 없다.
- 자바스크립트는 이러한 특성을 지닌, 싱글 쓰레드 언어이다.
- 이 정도로 이해하고 아래 코드를 한번 실행해보자!
// 이 코드를 실행시키면 '저도 출력해주세요.' 와 '저도 출력되고 싶어요 ㅠ_ㅠ' 는 영원히 출력되지 않는다.
// while (true) 라는 task가 끝나지 않기 때문에 이후 동작들은 작동하지 않는다.
// 이 예를 보면 자바스크립트가 왜 싱글 쓰레드 언어인지 알 수 있다.

setTimeout(() => {
  console.log("저도 출력해주세요.");
}, 0);

while (true) {
  console.log("놉!");
}

console.log("저도 출력되고 싶어요 ㅠ_ㅠ");

Q_2.  근데 어떻게 비동기 처리가..?

- 우리가 보통 자바스크립트가 사용되는 환경을 생각해보면, 많은 작업들이 동시에 처리되는 것을 알 수 있다.
- 예를 들어, 애니메이션 효과를 보여주면서 이름을 작성할 수 있고, 동시에 여러 http 요청을 처리할 수도 있다.
- 바로 오늘의 주제인 이벤트 루프가 이를 해결해준다.
- 이벤트 루프란 Callback Event Queue에서 하나씩 꺼내 동작시키는 루프를 말한다.
- 여기서 중요한 점은 자바스크립트가 비동기로 처리하는 것이 아니라 브라우저나 Node의 libuv 라이브러리가 이를 해결해주는 것이다.

 

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

 

- 위 그림에서 JS 안에 포함된 것만이 자바스크립트 엔진이다. 즉 그 외에 있는 것들은 브라우저나 Node.js에 포함된 것이다.
- 우선 자바스크립트는 코드를 실행시키면 싱글 쓰레드니까 당연히 코드를 차례대로 실행시킨다.
- 그러다가 코드 실행에 지연을 발생시킬 수 있는(블로킹) setTimeout이나 웹 요청 코드가 들어오면 이를 Web APIs에게 보내 실행하라고 넘기고 콜스택에서 제외시킨 다음, 다음 코드를 실행시킨다.
- 다른 코드들이 실행되는 동안 Web APIs의 작업이 끝나는대로 Callback Queue에 차례대로 들어와 콜 스택이 빈 상태가 될 때까지 기다린다.
- 콜스택이 비자마자 바로 Callback Queue에 있는 결과들이 이벤트 루프를 통해 콜 스택에 쌓여 실행된다.
- 이 실행 순서들은 뭔가 과정이 많아보이지만 우리에게는 마치 자바스크립트가 비동기 처리를 하는 것처럼 느끼게 한다.
- 아래 영상(12:48 ~ )을 보며 이벤트 루프 처리 과정에 대해 그림으로 이해해보자!

 

Q_3.  논블로킹?

- 여기서 나오는 또 하나의 중요한 개념! '자바스크립트는 논블로킹(Non-Blocking) 언어이다.'
- 그렇다면 논블로킹이 있다면 블로킹도 있을텐데 이 둘은 어떤 차이가 있을까?

- 위 내용을 통해 자바스크립트는 논블로킹이라는 특성을 통해 작업(task)이 멈추지 않고 실행되도록 한다는 것을 알 수 있다.
- 정리하자면 논블로킹은 이전 작업이 완료될때 까지, 기다리면서 멈추지 않고, 다음작업이 지연되지 않게 동작하는 패러다임이다.
- 이를 통해 오래걸리는 작업은 백그라운드에서 진행하며 완료 후, 이벤트 루프를 통해 태스크 큐를 거쳐 호출스택에 올라오길 기다리는 것이 가능하다!

- 참고로 자바스크립트에 예외로 블로킹이 가능한 메소드가 있는데, 그것은 바로... alert()이다!

 

Q_4.  그럼 동기/비동기랑 블로킹/논블로킹은 무슨 차이지?

- 동기/비동기는 A함수에서 B함수를 호출했을 때 A함수가 B함수의 결과값을 기다리느냐의 여부와 관련있다.
- 블로킹/논블로킹은 A함수에서 B함수를 호출했을 때 B함수에게 제어권이 넘어가느냐 마느냐의 여부와 관련있다.
- 그리고 이 네가지 개념은 서로 조합해서 어떤 차이가 있는지 아래 이미지를 통해 확인할 수 있다.

 

Q_5.  근데 왜 자바스크립트는 싱글 쓰레드일까?

- '쉬워서' !
- 자바스크립트가 멀티쓰레드로 실행되는 언어였다면 웹페이지에서 발생하는 동시성 문제에 대해 해결해야 했다.
- 이에 싱글 쓰레드로 구성해 멀티 쓰레드로 생길 수 있는 문제를 신경쓰지 않고 비동기 처리를 브라우저와 Node.js에 맡기는 것이다. (일종의 하청업체에게 일을 맡기는 느낌...이랄까?)

 

정리 ✨

- 처음에는 이벤트 루프에 대한 개념이 정말정말 낯설었다.
- 2번째 질문에 있던 그림을 아무리 봐도 이해가 잘 되지 않았는데, 결국 이를 알기 위해서는 기초 지식(비동기, 쓰레드, 블로킹 등)에 대해 알아야 한다는 것을 알았다.
- 결국은 '이래서 CS 공부를 해야하는구나!' 라는 사실을 알게 됐다. 뭐든지 기초가 중요한 법이니까.
- 기본을 탄탄히 다져서 어떤 낯선 개념을 마주하더라도 이해할 수 있도록 더욱 깊이 공부해야겠다는 다짐을 하게 됐다 ! 

 

참고

https://chanyeong.com/blog/post/44
https://stitchcoding.tistory.com/m/44
https://velog.io/@seokkitdo/%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84%EB%9E%80
반응형

댓글