자바스크립트는 왜 싱글 스레드를 선택했을까? 프로세스, 스레드, 비동기, 동기, 자바스크립트 엔진, 이벤트루프
- 목차
- 프로세스와 스레드
- 프로세스
- 싱글 스레드와 멀티 스레드
- 자바스크립트는 왜 싱글 스레드를 선택했을까
- 동기 vs 비동기
- 동기
- 비동기
- 자바스크립트로 비동기 처리하는 방법
- 자바스크립트 엔진
- 브라우저의 구조
- 동작 과정
- 프로세스와 스레드
1. 프로세스와 스레드
프로세스
- 동적인 상태, 실행되고 있는 컴퓨터 프로그래, 운영체제에서 할당하는 작업의 단위
- 노드, 웹브라우저 같은 프로그램 → 개별적인 프로세스
- 프로세스 간 메모리 등의 자원을 공유하지 않음 → 영향 x
스레드
- 프로세스 내에서 실행되는 흐름의 단위
- 프로세스는 스레드를 여러 개 생성해 여러 작업을 동시에 처리할 수 있음
- 스레드들은 부모 프로세스의 자원을 공유 → 영향 o
- 같은 주소의 메모리에 접근 가능 → 데이터 공유 가능
스레드는 프로세스가 할당받은 자원을 이용하는 실행의 단위
- 프로세스는 스레드를 여러 개 생성해 여러 작업을 동시에 처리할 수 있다. 스레드들은 부모 프로세스의 자원을 공유하여 영향을 받아 데이터 공유가 가능하다.
- 스레드는 프로세스 내에서 각각 Stack만 따로 할당받고 Code, Data, Heap 영역은 공유한다.
- 같은 프로세스 안에 있는 여러 스레드들은 같은 힙 공간을 공유한다. 반면에 프로세스는 다른 프로세스의 메모리에 직접 접근할 수 없다.
- 스레드는 싱글 스레드와 멀티 스레드로 나뉜다. 싱글 스레드는 직렬을 형태로 하나의 스레드가 하나의 작업만 수행하여 순서대로 처리하는 모습을 볼 수 있다. 멀티 스레드는 병렬로 일을 처리하며 여러가지 스레드를 한꺼번에 처리한다.
싱글 스레드
- 하나의 프로세스가 한번에 하나의 일만 처리하는 것
- 동기화 신경 x
멀티스레드
- 하나의 응용프로그램을 여러 개의 스레드로 구성하고 각 스레드로 하여금 하나의 작업을 처리하도록 하는 것
- ex) 멀티 스레드가 적용된 웹 브라우저 프로그램에서 하나의 스레드가 이미지 파일을 로드하고 있는 동안, 다른 스레드에서 사용자와 상호작용 가능
- 하나의 스레드에 문제가 발생하면 전체 프로세스가 영향을 받기에 주의 깊은 설계가 필요하다.
- 또한 스레드 간의 자원 공유로 동시성 문제가 발생한다.
- 동시성 문제란?
- 여러 개의 쓰레드가 같은 데이터에 접근하는 경우, 경우에 따라 동시성 문제가 발생할 수 있다.
여러 개의 쓰레드가 공유된 자원에 접근 할 때 데이터의 신뢰성을 보장받을 수 없는 없어 동기화 작업 필요
멀티 스레드는 프로그램을 병렬적으로 처리하여 향상된 사용자 응답을 제공하고,
자원을 효율적으로 사용하는 자바스크립트는 멀티 쓰레드를 놔두고 왜 싱글 쓰레드를 사용할까?
자바스크립트는 왜 싱글 스레드를 선택했을까?
- 자바스크립트는 웹페이지의 보조적인 기능을 수행하기 위해 브라우저에서 동작하는 경량 프로그래밍 언어를 도입하기로 결정하고 만들어진 언어가 자바스크립트 이다.
- 웹사이트를 구현하던 개발자들에게 자바라는 언어는 다소 무겁고 어려운 언어였기 때문에, 브랜던 아이크라는 사람을 스카우트하여 ‘자바스크립트’가 탄생되었다.
- 왜 무겁고 어려운 언어라 생각했을까? → 멀티 스레드 모델은 프로그래밍 난이도가 높다.
- 멀티 스레드로 구현된 서비스에서는 이 동시성 문제에 대해 많이 신경쓴다고 한다. 자바스크립트는 멀티 스레드 환경에서 발생할 수 있는 복잡한 시나리오를 신경쓸 필요 없다.
실제로 구글의 chrome 브라우저도 기존 웹 페이지에서 엄청난 동시성 문제를 일으킬 수 있다는 이유로 단일 웹 사이트 페이지의 자바스크립트 코드가 동시에 실행되는 것을 허용하지 않는다.
자바스크립트는 어떻게 한번에 여러 요청을 처리할까?
비동기 vs 동기
동기 처리
자바스크립트 엔진은 싱글 쓰레드 방식으로 실행되기 때문에 하나의 실행 컨텍스트 스택을 갖는다. 이는 함수를 실행 할 수 있는 창구가 단 하나이며, 동시에 2개이상의 함수를 동시에 실행시킬 수 없다는 의미이다.
또 이 말은 즉, 처리에 시간이 걸리는 태스크를 실행하는 경우 블로킹(blocking) 이 발생한다.
- 현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식을 동기 처리 라고 한다.
- 동기 처리 방식은 태스크를 순서대로 하나씩 처리하므로 실행 순서가 보장된다는 장점이 있지만,
- 앞선 태스크가 종료할 때까지 이후 태스크들이 블로킹 되는 단점이 있다.
function sleep(func, delay) {
const delayUntil = Date.now() + delay;
while (Date.now() < delayUntil);
func();
}
function foo (){
console.log('foo')
}
function bar () {
console.log('bar')
}
sleep(foo, 3*1000);
bar();
비동기 처리
- 현재 실행중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식을 비동기 처리라고 한다.
- 여러개의 태스크를 동시에 처리할 수 있다.(정확히 말하자면 사람이 인지할 수 없을 정도로 찰나의 시간으로 순차적인 실행이 이루어지기 때문에 동시에 실행되는 것과 다름없게 느껴진다.)
- 태스크의 실행 순서가 보장되지 않는 단점이 있다.
- 비동기 처리를 수행하는 비동기 함수는 전통적으로 콜백 패턴을 사용
function foo (){
console.log('foo')
}
function bar () {
console.log('bar')
}
setTimeout(foo, 3000);
bar();
비동기의 주요 사례(비동기 처리 방식으로 작동)
- dom element의 이벤트 핸들러
마우스, 키보드 입력(click, keydown 등)
페이지 로딩 (DOMContentLoaded 등) - 타이머
타이머 api (setTimeout, setInterval 등)
애니메이션 API (requestAnimationFrame) - 서버에 자원 요청 및 응답
fetch API
AJAX(XHR)
4. 자바스크립트 비동기 처리 방식
- 자바스크립트는 싱글 쓰레드로 동작한다는 것
- 싱글스레드 방식은 한 번에 하나의 태스크만 처리할 수 있다는 것을 의미
- 하지만 브라우저가 동작하는 것을 살펴보면 많은 태스크가 동시에 처리되는 것처럼 느껴진다.
- ex) html 요소가 애니메이션 효과를 통해 움직이면서 이벤트를 처리하기도 하고, http요청을 통해 서버로부터 데이터를 가지고 오면서 렌더링하기도 한다.
- 이처럼 자바스크립트의 동시성을 지원하는 것이 이벤트루프
- 이벤트루프는 브라우저에 내장되어 있는 기능 중에 하나
자바스크립트 엔진
자바스크립트 엔진(Javascript Engine)이란?
- 자바스크립트 코드를 해석하고 실행하는 인터프리터
- 구글의 V8 자바스크립트 엔진을 비롯한 대부분의 자바스크립트 엔진은 크게 2개의 영역으로 구분할 수 있다.
- Memory Heap: 선언된 변수들이 메모리 할당이 이뤄지는 곳입니다.
- Call Stack: 코드가 실행될 때 호출 스택이 쌓이는 곳입니다. (호출된 함수가 call stack에 push 됩니다.) 자바스크립트 엔진은 단 하나의 콜 스택을 사용하기 때문에 실행 중인 실행 컨택스트가 종료되어 콜 스택에서 제거되기 전까지는 다른 어떤 태스크도 실행되지 않는다.
- 자바스크립트 언어 자체가 비동기 동작을 지원하는 것은 아니다. 자바스크립트 엔진은 단순히 태스크가 요청되면 콜 스택을 통해 요청 작업을 순차적으로 실행할 뿐이다.
브라우저(Web Browser)의 구조
비동기 처리에서 소스코드의 평가와 실행을 제외한 모든 처리는 자바스크립트 엔진을 구동하는 환경인 브라우저 또는 node.js가 담당한다.
실제로 자바스크립트가 구동되는 환경인 웹 브라우저에는 여러 개의 Thread가 사용됩니다.
자바스크립트 엔진 +
Web APIs Web API는 브라우저에서 자체 지원하는 api이다. Web API는 DOM이벤트, AJAX, setTimeout등의 비동기 작업등을 수행할 수 있도록 api를 지원한다.
태스트 큐 setTimeout, setInterval 과 같은 비동기 함수의 콜백 함수 또는 이벤트 핸들러가 일시적으로 보관되는 영역, 태스크 큐는 하나의 큐로 이루어져 있지 않는다. Microtask Queue, Animation Frames 등 여러개의 큐로 이루어져 있다.
이벤트루프 Call Stack과 task Queue의 상태를 체크하여, Call Stack이 빈 상태가 되면, task Queue에 있는 콜백함수들을 순차적으로 Call Stack으로 밀어넣어 주는 역할을 합니다. 이러한 반복적인 행동을 틱(tick) 이라 부릅니다.
‘ 로 구성되어 있다.
자바스크립트 동작과정 코드
http://latentflip.com/loupe/ <- 여기서 밑에 코드 실행시키기
1.
function second() {
setTimeout(function(){
console.log('2+2')
}, 2000)
}
function first() {
console.log('1+1');
second();
console.log('3+3');
}
first();
2. setTimeout(callback, 0)
0초 후에 실행한다는 말은 즉시 실행하니 코드가 순서대로 출력될 것이라 생각할 수 있다.
function second() {
setTimeout(function(){
console.log('2+2')
}, 0)
}
function first() {
console.log('1+1');
second();
console.log('3+3');
}
first();
결론
- 동기적 프로그래밍이 문제가 되지 않던 시절도 있었지만, 현재의 웹은 너무나도 커지고 복잡해졌기 때문에 사용자의 동시 다발적인 요청에 빠르게 응답하기 위하여 비동기적 프로그래밍이 불가피해졌다.
- 자바스크립트는 Single Thread 프로그래밍 언어라 한 번에 하나씩 밖에 실행할 수 없지만, Web API, Callback Queue, Event Loop 덕분에 멀티 스레드처럼 동시성을 지니고 있다.
참고문서
모던 자바스크립트 - 비동기
https://chanyeong.com/blog/post/44
https://velog.io/@gil0127/싱글스레드Single-thread-vs-멀티스레드-Multi-thread-t5gv4udj
https://student513.tistory.com/74
https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html
https://gyofeel.github.io/js/nodejs/web/Javascript와-Nodejs는-모두-싱글-스레드에서-실행되는가/