자바스크립트는 싱글 쓰레드 언어인데 비동기 처리가 가능하다?
글을 시작하기 전 알아둬야 할 지식
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
반응형
'Programming > 4. JavaScript & React' 카테고리의 다른 글
011_'절대값이 2^53보다 크거나 같은 숫자 리터럴은 너무 커서 정수로 정확하게 표시할 수 없습니다.' (0) | 2022.03.15 |
---|---|
010_for, forEach, map(재정리 ver.) 👀 (0) | 2022.03.14 |
008_스코프(Scope) 🔭 (0) | 2022.02.23 |
007_TDD, 그리고 Storybook (0) | 2022.02.14 |
006_코어 자바스크립트 챌린지_3 (0) | 2022.02.02 |
댓글