비동기 vs 병렬Javascript/Javascript 지식2025. 9. 18. 23:30
Table of Contents
비동기(Asynchronous)
- 작업이 완료될 때까지 기다리지 않고, 다음 코드를 바로 실행하는 방식
- 한 스레드 내에서도 가능함 (JS처럼 싱글 스레드에서도 구현 가능)
- 작업 순서와 실행 시간 분리
- 주로 I/O, 네트워크 요청, 타이머 등에서 사용
console.log("시작");
setTimeout(() => {
console.log("비동기 완료");
}, 1000);
console.log("끝");
Time 0ms: 시작 출력
Time 0ms: setTimeout 등록 → 백그라운드로 이동
Time 0ms: 끝 출력
Time 1000ms: 이벤트 루프가 Task Queue에서 콜백 실행 → "비동기 작업 완료" 출력
- JS는 싱글 스레드지만, 이벤트 루프 덕분에 비동기처럼 동작 가능.
병렬(Parallel)
- 두 개 이상의 작업이 동시에 물리적으로 실행되는 것
- 멀티스레드, 멀티코어 CPU에서 가능
- 각 작업이 서로 독립적으로 동시에 수행됨
- 실제 CPU 코어에서 동시에 실행
- 메인 스레드가 막히지 않고, Worker가 연산을 병렬 처리
예: 웹 서버에서 동시에 여러 요청 처리, GPU 연산 등
작업1: ████
작업2: ████ <- 같은 시간대에 동시에 실행
실행예시~
// main.js
console.log("메인 스레드 시작");
const worker = new Worker("worker.js");
worker.onmessage = (e) => {
console.log("Worker 메시지:", e.data);
};
console.log("메인 스레드 끝");
// worker.js
// 병렬로 실행되는 스레드
let sum = 0;
for (let i = 0; i < 1e9; i++) sum += i;
postMessage("Worker 작업 완료");
메인 스레드: 시작 출력
메인 스레드: Worker 생성 → 병렬로 작업 시작
메인 스레드: 끝 출력
Worker 스레드: 독립적으로 연산 수행
Worker 완료 → 메시지 전달 → 메인 스레드에서 출력
// 예상 출력 순서
메인 스레드 시작
메인 스레드 끝
Worker 메시지: Worker 작업 완료
- 메인 스레드 실행
- console.log("메인 스레드 시작") → 즉시 출력
- Worker 생성 → worker.js 실행 → 새로운 스레드에서 연산 시작 (메인 스레드와 병렬)
- console.log("메인 스레드 끝") → 즉시 출력
- Worker 스레드 실행
- for 루프에서 1e9 연산 수행 → 메인 스레드와 독립적으로 진행
- 연산 완료 후 postMessage("Worker 작업 완료") → 메인 스레드 이벤트 처리
만약 병렬 연산이 먼저 끝나면 console이 먼저 찍힐까 ?!
- 메인 스레드에서 동기 코드가 먼저 실행되는 한, Worker가 먼저 끝나더라도 메인 스레드 콘솔 출력보다 먼저 찍히는 건 불가능!
Call Stack 우선순위
- 메인 스레드의 Call Stack이 먼저 실행됨 → 동기 코드가 끝날 때까지 다른 콜백(Worker 메시지 포함)은 실행되지 않음.
- Worker가 병렬로 연산을 끝냈다고 해도, 메시지는 Task Queue에 들어감 → 이벤트 루프가 Call Stack이 비었을 때 실행
이유!!
- 메인 스레드 Call Stack:
- "메인 스레드 시작" 출력
- Worker 생성 → Worker 병렬 실행
- "메인 스레드 끝" 출력
- Worker:
- 연산 완료 → 메시지 Task Queue에 추가
- 이벤트 루프:
- Call Stack이 비었을 때 Task Queue에서 "Worker 메시지" 실행
- 동기 코드 > Task Queue 순은 항상 유지
- Worker가 빨리 끝나더라도 메인 스레드의 동기 console.log보다 먼저 출력 불가
둘 다, call stack 밖에서 일어나는거 아니야 ??
- 둘 다 병렬 아닌가..?
- 둘 다 병렬처럼 보이지만 성격이 조금 다름!
API 호출 (I/O 병렬)
- fetch 같은 API 요청은 브라우저/Node.js 런타임의 백그라운드 스레드에서 처리됨
- CPU 연산과 상관없이 I/O가 병렬 처리되는 형태
- CPU를 거의 사용하지 않음
- JS 엔진이 직접 처리하지 않음 → 브라우저/Node.js 런타임이 백그라운드에서 처리
- 결과만 이벤트 루프를 통해 JS로 전달 → Call Stack이 비었을 때 콜백 실행
fetch("/api/1").then(() => console.log("API 1 완료"));
fetch("/api/2").then(() => console.log("API 2 완료"));
- 실제로 동시에 여러 API 요청 처리 가능 → JS는 기다리지 않고 다음 코드 실행
- JS 싱글 스레드에서 “병렬 I/O”라고 부름
Worker 연산 (CPU 병렬)
- Worker는 CPU 코어에서 실제 연산을 병렬 처리
- 메인 JS 스레드와 독립적인 스레드에서 실행 → 진짜 병렬
const worker = new Worker("worker.js");
항목 API 호출 (I/O) vs Worker (CPU)
| 목적 | I/O 요청 처리 | CPU-heavy 연산 |
| CPU 사용 | 거의 없음 | 많이 사용 가능 |
| 실행 위치 | 런타임 백그라운드 스레드 | 별도 JS Worker 스레드 |
| JS 엔진 참여 | 결과만 이벤트 루프 통해 처리 | Worker 자체에서 JS 엔진 실행 |
| 병렬성 | I/O 병렬 | CPU 병렬 |
'Javascript > Javascript 지식' 카테고리의 다른 글
| Javascript는 싱글 스레드인데 여러 일을 하네..? (이벤트 루프) (0) | 2025.09.18 |
|---|---|
| type vs interface (0) | 2025.09.18 |
| lodash curry, flow (0) | 2024.01.03 |
| falsy value, == vs === 연산자 (2) | 2022.10.31 |
| 이벤트 버블링/캡쳐/위임 (1) | 2022.09.16 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!