이벤트 루프 기반 비동기 처리 (Event Loop Based Asynchronous Processing)

Ⅰ. 이벤트 루프 개념

1. 정의 및 특징

이벤트 루프(Event Loop)는 단일 스레드에서 이벤트 큐를 순회하며 콜백 함수를 디스패치하는 비동기 처리 아키텍처다. 멀티스레딩 없이 동시성을 달성하는 핵심 메커니즘이다.

비유: 식당 주방장이 혼자서 주문서를 하나씩 확인하고, 조리가 오래 걸리는 음식은 오븐에 맡겨놓고 다음 주문을 처리하는 방식과 같다.

┌─────────────────────────────────────────────────┐
│                 Event Loop                       │
│                                                   │
│   ┌─────────┐    ┌──────────┐    ┌──────────┐   │
│   │  Event   │───>│ Dispatch  │───>│ Callback │   │
│   │  Queue   │    │  & Exec  │    │ Complete │   │
│   └─────────┘    └──────────┘    └──────────┘   │
│        ^                               │          │
│        └───────────────────────────────┘          │
└─────────────────────────────────────────────────┘
┌─────────────────── Single Thread Timeline ───────────────────┐
│                                                              │
│  [A]──request──>[B]──request──>[A]──callback──>[C]──...     │
│   non-blocking   non-blocking   result                       │
│                                                              │
│  Legend: [A],[B],[C] = async operations                      │
└──────────────────────────────────────────────────────────────┘

Ⅱ. 동작 원리

1. 논블로킹 I/O (Non-blocking I/O)

I/O 연산이 완료될 때까지 스레드를 차단하지 않고 즉시 반환하며, 작업 완료 시 콜백을 큐에 등록한다.

2. 이벤트 루프의 5단계 (Node.js 기준)

단계이름설명
1TimerssetTimeout, setInterval 만료된 콜백 실행
2Pending Callbacks이전 루프에서 지연된 I/O 콜백 실행
3Poll새로운 I/O 이벤트 수집 및 실행
4ChecksetImmediate 콜백 실행
5Closeclose 이벤트 콜백 실행
┌──────────────────────────────────────────────────────────┐
│                   Event Loop Phases                      │
│                                                          │
│   ┌────────┐  ┌────────┐  ┌──────┐  ┌───────┐  ┌─────┐│
│   │ Timers │─>│Pending │─>│ Poll │─>│ Check │─>│Close││
│   └────────┘  │Callback│  └──────┘  └───────┘  └─────┘│
│      ^        └────────┘     │                         │
│      └───────────────────────┘  (다시 반복)              │
│                                                          │
│   [Microtask Queue: Promise.then, process.nextTick]     │
│   > 각 페이즈 사이마다 우선 실행                          │
└──────────────────────────────────────────────────────────┘

3. 구현체별 특징

플랫폼엔진특징
Node.jslibuvC++ 기반, 파일 I/O + 네트워크 모두 비동기
Browser JSV8/SpiderMonkeyWeb API 사용, UI 렌더링과 병행
Python asyncioasync/await코루틴 기반, asyncio.run() 진입점
GogoroutineM:N 스케줄링, runtime에 이벤트 루프 내장

비유: 이벤트 루프의 페이즈는 우체부가 아침에 배달(Timers), 미처 못한 편지(Pending), 새 편지 수거(Poll), 등기 확인(Check), 마감(Close) 순으로 돌리는 일과와 같다.

Ⅲ. 비동기 처리 흐름

1. 콜백 기반 vs 프로미스 기반

┌────────────────── Callback Style ──────────────────┐
│                                                     │
│  readFile("data.txt", function(err, data) {        │
│      if (err) throw err;    // 콜백 지옥 가능       │
│      console.log(data);                             │
│  });                                                │
│                                                     │
└─────────────────────────────────────────────────────┘

┌────────────────── Promise Style ───────────────────┐
│                                                     │
│  readFile("data.txt")                               │
│      .then(data => console.log(data))               │
│      .catch(err => console.error(err));             │
│                                                     │
│  // async/await 변환                                 │
│  const data = await readFile("data.txt");           │
│                                                     │
└─────────────────────────────────────────────────────┘

2. 마이크로태스크와 매크로태스크

구분예시실행 시점
MicrotaskPromise.then, queueMicrotask현재 페이즈 종료 직후, 다음 페이즈 이전
MacrotasksetTimeout, setImmediate다음 이벤트 루프 틱(tick)

Ⅳ. 장단점 및 한계

1. 장점

  • 스레드 생성/컨텍스트 스위칭 오버헤드 없음
  • 메모리 사용량 적음 (단일 스레드)
  • 수만 개의 동시 연결 처리 가능 (C10K 문제 해결)
  • 동기 코드와 비슷한 제어 흐름으로 작성 가능

2. 한계: CPU 연산 집약적 작업

┌──────── CPU-Bound Blocking ────────┐
│                                     │
│  [Event Loop]──[Task A]────────────>│ BLOCKED!
│                   │                 │ (다른 이벤트 전부 지연)
│                   │  CPU 100%      │
│                   │  10초 소요     │
│                   ▼                 │
│              [완료]                  │
│  [Task B, C, D... 지연됨]          │
│                                     │
└─────────────────────────────────────┘

해결책: Worker Thread 분리, 클러스터 모드 (멀티프로세스), C++ Addon 오프로딩

Ⅴ. 지식 그래프

이벤트 루프 기반 비동기 처리
├── 핵심 개념
│   ├── 단일 스레드 이벤트 구동 아키텍처
│   ├── 논블로킹 I/O
│   └── 콜백 큐 순회 및 디스패치
├── 이벤트 루프 페이즈
│   ├── Timers (setTimeout/setInterval)
│   ├── Pending Callbacks (지연된 I/O)
│   ├── Poll (새 이벤트 수집)
│   ├── Check (setImmediate)
│   └── Close (닫기 콜백)
├── 구현체
│   ├── libuv (Node.js)
│   ├── Browser Web API
│   ├── Python asyncio
│   └── Go runtime scheduler
├── 비동기 패턴
│   ├── Callback (콜백 지옥)
│   ├── Promise (then/catch/finally)
│   └── Async/Await (코루틴)
├── 장점
│   ├── 스레드 오버헤드 제거
│   ├── 적은 메모리 사용
│   └── C10K 문제 해결
└── 한계 및 해결책
    ├── CPU-bound 작업 시 블로킹
    ├── Worker Thread 분리
    └── 클러스터 (멀티프로세스)

약어 정리

약어Full Name
libuvLibrary for UV (Unified Virtualization)
I/OInput/Output
APIApplication Programming Interface
C10KClient 10,000 Problem

3줄 어린이 설명

컴퓨터가 한 사람처럼 일할 때, 기다리지 않고 여러 일을 번갈아 하는 방법입니다. 주문이 들어오면 오븐에 넣고 다른 주문을 받는 식당 주방장과 같아요. 단, 계산이 아주 많이 필요한 일은 다른 도우미에게 맡겨야 합니다.