Polling 방식에 대해 설명해 주세요.
CPU가 주기적으로 장치의 상태를 직접 확인하여 이벤트 발생 여부를 감지하는 I/O 처리 방식입니다.
핵심 개념
| 항목 | 내용 |
| 방식 | CPU가 반복적으로 장치의 상태 레지스터를 읽어서 확인 |
| 주체 | CPU가 능동적으로 확인 (장치는 수동) |
| 동기/비동기 | 동기적 — CPU가 확인할 때까지 이벤트를 알 수 없음 |
| 별칭 | Busy Waiting, Programmed I/O |
폴링의 동작 방식
CPU: 데이터 준비됐어? → 장치: 아니요
CPU: 데이터 준비됐어? → 장치: 아니요
CPU: 데이터 준비됐어? → 장치: 아니요 ← CPU가 계속 확인 (Busy Waiting)
CPU: 데이터 준비됐어? → 장치: 네! ← 감지
CPU: 데이터 읽기 처리
┌─────────────────────────────────────────────┐
│ 폴링 루프 │
│ │
│ while (true) { │
│ status = read_device_status(); │
│ if (status == READY) { │
│ data = read_device_data(); │
│ process(data); │
│ break; │
│ } │
│ // 준비 안 됐으면 다시 반복 │
│ } │
│ │
└─────────────────────────────────────────────┘
폴링 vs 인터럽트
| 항목 | 폴링 (Polling) | 인터럽트 (Interrupt) |
| 주체 | CPU가 장치 상태를 확인 | 장치가 CPU에 알림 |
| CPU 사용 | 이벤트 없어도 CPU 점유 | 이벤트 발생 시에만 CPU 사용 |
| 응답 속도 | 폴링 주기에 의존 | 즉시 감지 가능 |
| 구현 복잡도 | 단순 | IDT, ISR 등 구조 필요 |
| 컨텍스트 스위칭 | 없음 | 모드 전환 + 레지스터 저장 오버헤드 |
| 적합한 상황 | 이벤트가 매우 빈번한 경우 | 이벤트가 불규칙한 경우 |
[폴링]
CPU 시간: ████████████████████████████████ (항상 점유)
장치: ─────────────────────●────────── (가끔 이벤트)
↑
이벤트 발생했지만
다음 폴링까지 대기해야 감지
[인터럽트]
CPU 시간: ●━━● ●━━━━● ●━● (필요할 때만)
장치: ─────●────────●──────────────
↑ ↑
즉시 감지 즉시 감지
폴링의 장단점
| 장점 | 단점 |
| 구현이 단순 | CPU 시간 낭비 (Busy Waiting) |
| 모드 전환 오버헤드 없음 | 이벤트 없을 때도 CPU 점유 |
| 인터럽트 레이턴시 없음 | 응답 시간이 폴링 주기에 의존 |
| 이벤트 순서가 예측 가능 | 다중 장치 관리 시 비효율적 |
| 이벤트가 빈번하면 효율적 | 이벤트가 드물면 매우 비효율적 |
폴링이 유리한 경우
1. 이벤트가 매우 빈번할 때
[초당 수십만 패킷을 처리하는 고성능 네트워크]
인터럽트 방식:
패킷마다 인터럽트 → 모드 전환 + 상태 저장/복원 → 오버헤드 폭발
→ "인터럽트 폭풍 (Interrupt Storm)"
폴링 방식:
지속적으로 NIC 상태 확인 → 패킷이 거의 항상 있음
→ 모드 전환 없이 빠르게 처리
→ 오히려 인터럽트보다 효율적
2. 응답 시간이 극도로 짧아야 할 때
인터럽트: 발생 → 상태 저장 → IDT 조회 → ISR 실행 (~수 μs 지연)
폴링: 확인 → 바로 처리 (~수십 ns 지연)
실시간 시스템(자동차 ECU, 항공기 제어)에서는
확정적인 응답 시간이 중요 → 폴링이 유리할 수 있음
3. 장치가 거의 항상 준비 상태일 때
CPU에 가까운 고속 장치 (예: CPU 내장 센서, 고속 SSD)
→ 확인할 때마다 거의 항상 데이터가 있음
→ 폴링의 "헛수고"가 거의 없음
→ 인터럽트 오버헤드를 아낄 수 있음
실제 사용 사례
| 사례 | 방식 | 이유 |
| Linux NAPI (네트워크) | 인터럽트 + 폴링 하이브리드 | 패킷 폭주 시 인터럽트 → 폴링 전환 |
| NVMe SSD | 폴링 모드 지원 | 초저지연 I/O에서 인터럽트 오버헤드 제거 |
| DPDK (고성능 네트워크) | 폴링 전용 | 초당 수백만 패킷 처리 시 인터럽트 감당 불가 |
| 임베디드/실시간 시스템 | 폴링 | 확정적 응답 시간 보장 |
| 일반 키보드/마우스 | 인터럽트 | 이벤트가 드문데 폴링하면 CPU 낭비 |
| 일반 디스크 I/O | 인터럽트 | I/O 완료까지 수 ms → 폴링 시 CPU 낭비 |
Linux NAPI — 하이브리드 방식
[일반 상태 — 인터럽트 방식]
패킷 도착 → NIC 인터럽트 → ISR 실행 → 패킷 처리
[패킷 폭주 감지 — 폴링으로 전환]
패킷 폭주 감지 → 인터럽트 비활성화 → 폴링 모드 진입
│
▼
while (패킷이 있는 동안) {
패킷 = NIC에서 읽기(); // 폴링
처리(패킷);
}
│
▼
패킷이 줄어듦 → 다시 인터럽트 모드로 복귀
이점:
- 평소에는 인터럽트로 CPU 절약
- 폭주 시에는 폴링으로 인터럽트 오버헤드 제거
Java에서의 폴링 예시
// 1. 폴링 방식 — CPU를 계속 점유
while (true) {
if (queue.peek() != null) { // 큐에 데이터 있는지 계속 확인
Object data = queue.poll();
process(data);
}
// 데이터 없어도 루프 반복 → CPU 낭비
}
// 2. 인터럽트(블로킹) 방식 — CPU를 양보
while (true) {
Object data = queue.take(); // 데이터 올 때까지 스레드 Sleep
process(data); // 데이터 도착 시 깨어남
// 대기 중에는 CPU를 다른 스레드에 양보
}
// 3. 하이브리드 — 폴링 + Sleep
while (true) {
Object data = queue.poll();
if (data != null) {
process(data);
} else {
Thread.sleep(10); // 10ms 쉬고 다시 확인 → CPU 낭비 줄임
}
}
CPU 사용률 비교:
[순수 폴링] CPU: ████████████████████████ (100%)
[하이브리드] CPU: █░░█░░█░░█░░█░░░░░░░░░ (~30%)
[인터럽트/블로킹] CPU: █░░░░░░░█░░░░░░░░░░░░░ (~10%)
핵심 정리
폴링: CPU가 "데이터 있어?" 하고 계속 물어보는 방식
장점: 단순하고, 이벤트가 빈번하면 효율적
단점: 이벤트가 드물면 CPU 낭비
실무에서는 순수 폴링보다
인터럽트와 폴링을 결합한 하이브리드 방식을 주로 사용
→ 평소: 인터럽트 (CPU 절약)
→ 이벤트 폭주: 폴링 (오버헤드 절약)