1. 이벤트 루프(Event Loop)란?
이벤트 루프는 자바스크립트의 비동기 처리 메커니즘입니다. 자바스크립트는 단일 스레드에서 동작하기 때문에, 동시에 여러 작업을 처리하지 못합니다. 하지만 이벤트 루프 덕분에 비동기 작업을 통해 여러 일을 동시에 처리하는 것처럼 보이게 합니다.
비동기에 대해 알기 위해선 동기에 대해 알아야 하고 그러기 위해선
프로세스와 스레드가 무엇인지 알아야합니다.
프로세스와 스레드의 차이
- 프로세스: 프로그램 실행의 단위로, 독립된 메모리와 자원을 가집니다.
- 스레드: 프로세스 내부에서 실행 흐름의 단위입니다. 하나의 프로세스는 여러 스레드를 가질 수 있습니다.
복잡하게 적어놨지만 간단히 말하면 한 개의 프로그램을 돌리는데 한 개의 프로세스가 필요하고
프로세스 내부에서 모든 작업을 수행하다 프로세스 내부에서 더 세부적인 실행 단위인 스레드를 만들었다.
자바스크립트는 왜 싱글 스레드인가?
- 싱글 스레드: 자바스크립트는 한 번에 하나의 작업만 수행할 수 있는 언어입니다. 즉, 동시에 여러 작업을 처리하지 않고, 한 작업이 끝나야 다음 작업을 처리할 수 있습니다.
- 이유: 자바스크립트는 처음 웹 페이지와 사용자가 상호작용하는 UI 작업을 위해 설계되었습니다. 여러 작업이 동시에 실행되면 경합(Conflict) 문제가 발생할 수 있어, 예측 가능한 동작을 보장하기 위해 싱글 스레드 방식을 채택했습니다.
경합(Conflict)은 컴퓨터 시스템에서 여러 작업이나 프로세스가 동시에 같은 자원에 접근하려고 할 때 발생하는 문제를 의미합니다. 경합은 특히 멀티스레드 프로그래밍이나 병렬 처리 환경에서 자주 발생하며, 동시성 문제의 주요 원인 중 하나입니다.
경합(Conflict)이 발생하는 상황
- 공유 자원 접근:
- 여러 스레드나 프로세스가 동시에 같은 자원(예: 변수, 파일, 데이터베이스 등)을 읽거나 수정하려고 할 때 발생합니다.
- 예를 들어, 두 스레드가 동시에 같은 변수에 접근하여 값을 변경하려고 하면, 값이 의도와 다르게 변경될 수 있습니다.
- 데이터 불일치:
- 경합이 발생하면 자원에 대한 접근 순서가 예측할 수 없게 되며, 데이터의 일관성이 깨질 수 있습니다.
- 예를 들어, 하나의 스레드가 데이터를 읽고 수정하는 중에 다른 스레드가 그 데이터를 읽으면 잘못된 값이 사용될 수 있습니다.
let counter = 0;
function increment() {
for (let i = 0; i < 1000; i++) {
counter += 1; // 여러 스레드가 동시에 이 코드를 실행하면 문제가 발생할 수 있습니다.
}
}
increment();
increment();
console.log(counter); // 기대값은 2000이지만, 경합이 발생하면 결과가 예상과 다를 수 있습니다.
스레드란?
- 스레드: 프로그램이 CPU에서 작업을 처리하는 흐름의 단위입니다. 여러 스레드를 사용하면 여러 작업을 동시에 처리할 수 있습니다.
- 싱글 스레드: 자바스크립트는 하나의 스레드만 사용해 모든 작업을 순차적으로 처리합니다.
이는 자바스크립트의 Run-to-completion 이라는 특징인데 말그대로 앞의 것이 끝나기 전까지 뒤의 명령이 실행되지 않음을 의미합니다
자바스크립트 싱글 스레드의 동작 방식
- 호출 스택(Call Stack):
- 자바스크립트는 작업을 처리할 때 호출 스택을 사용합니다.
- 호출 스택은 함수 호출이 쌓이는 구조로, 먼저 쌓인 함수가 나중에 실행됩니다 (LIFO: Last In, First Out).
- 작업 처리 순서:
- 자바스크립트는 호출 스택에 쌓인 함수들을 순서대로 처리합니다.
- 각 작업이 완료되면 스택에서 제거하고, 다음 작업을 처리합니다.
호출 스택의 동작 예시
function first() {
console.log('첫 번째 함수 실행');
}
function second() {
first(); // first() 호출
console.log('두 번째 함수 실행');
}
second(); // second() 호출
동작 방식
- second() 함수가 호출되면 호출 스택에 쌓입니다.
- second() 내부에서 first()가 호출되면 first()가 호출 스택에 추가됩니다.
- first() 함수가 실행되고 완료되면 스택에서 제거됩니다.
- 이후 second()가 실행되고 스택에서 제거됩니다.
기본적인 stack의 구조로 함수를 적재하고 사용 후 반환