
우리는 너무 자연스럽게 이렇게 생각한다.
sleep(1)→ 1초 기다림
근데 진짜로 누가 1초를 세고 있을까?
언어? 런타임?
아니면 CPU가 속으로 “하나… 둘…” 하고 있을까?
결론부터 말하면:
❌ 프로그래밍 언어는 “초를 세지 않는다”
✅ OS + 하드웨어 타이머 + 스케줄러가 시간을 만든다
이 글에서는 그걸 끝까지 파고들어서 설명해보겠다.
sleep의 진짜 의미우리가 쓰는 대부분의 sleep은 이런 의미다:
"지금 실행을 멈추고,
이 시각 이후에 다시 실행되게 해줘"
즉, 핵심은 이거다:
❌ "1초 동안 기다리기"
✅ "1초 후에 깨워달라고 예약하기"
이건 엄청 중요한 차이다.
time.sleep(1)이 실행되면 내부에서 이런 일이 일어난다:
[언어 코드]
↓
[런타임]
↓
[OS 시스템콜 (nanosleep 등)]
↓
[커널 타이머 등록]
↓
[하드웨어 타이머 인터럽트]
↓
[스레드 깨움]
↓
[스케줄러가 CPU 다시 할당]
한 줄 요약:
sleep은 “시간을 재는 함수”가 아니라
“미래 시점에 실행을 예약하는 시스템”이다
예를 들어 Python:
import time
time.sleep(1)
이건 내부적으로 대략 이렇게 된다:
nanosleep(1초)
Java:
Thread.sleep(1000);
→ OS 타이머 사용
Rust:
std::thread::sleep(Duration::from_secs(1));
→ 역시 OS 타이머
👉 즉:
대부분의 언어는 직접 시간을 재지 않는다
그냥 OS에게 맡긴다
여기부터가 진짜 핵심이다.
OS는 “타이머 하나”로 동작하지 않는다.
"지금 몇 시냐?"
이걸 담당한다.
특징:
예:
123456789012 ticks → ns 변환
👉 핵심:
시간을 “세는 게 아니라”
이미 흐르고 있는 값을 읽는다
"이 시각에 인터럽트 발생시켜라"
역할:
👉 핵심:
시간을 체크하는 게 아니라
미래에 알람을 맞춘다
OS 내부에는 타이머 큐가 있다.
sleep(1)
→ 현재 시간 + 1초 = deadline
→ 타이머 큐에 등록
구조:
👉 그래서 OS는:
가장 가까운 타이머만 신경쓴다
여기서 많은 사람들이 틀린다.
시간이 끝났다고 바로 실행되는 게 아니다
타이머 만료
→ 스레드 "깨울 준비됨"
→ 스케줄러가 CPU 줄 때까지 기다림
👉 핵심:
sleep 끝 = 실행 시작 ❌
sleep 끝 = 실행 가능 상태 ⭕
OS 아래에는 하드웨어 타이머가 있다.
대표 구조:
[카운터] 계속 증가
[비교기] 특정 값 도달 시 인터럽트 발생
예:
현재: 1000
목표: 2000
→ 2000 되면 인터럽트 발생
👉 이게 진짜 “시간”이다.
많은 사람들이 궁금해하는 부분:
왜
sleep(1)은 1초가 아닐까?
이유는 여러 개다.
1ns 요청 → 실제는 1ms 단위일 수도 있음
시간 끝남 → CPU 없음 → 대기
"비슷한 타이머들 한 번에 깨우자"
→ 일부러 늦춤
setTimeout(() => {}, 0)
→ 즉시 실행 ❌
→ 큐에 들어감 ⭕
👉 결론:
sleep은 정확한 시간이 아니라
최소 대기 시간 보장이다
CPU를 놓는다
OS가 깨워준다
while (time < target) {}
특징:
👉 OS 커널에서도 둘을 명확히 구분한다.
2026-03-18 12:00:00
문제:
시스템 시작 이후 시간
특징:
👉 핵심:
sleep은 거의 항상 monotonic 기반이다
while True:
do_something()
time.sleep(1)
next_time = time.monotonic()
while True:
next_time += 1
do_something()
sleep(next_time - time.monotonic())
👉 이유:
sleep 누적 오차 제거
이 글의 핵심을 한 줄로 정리하면:
sleep은 시간을 재는 함수가 아니다
미래에 실행을 예약하는 시스템이다
그리고 그 아래에는:
이 모든 게 얽혀 있다.
sleep = (현재 시간 + duration) → OS 타이머 등록 → 인터럽트 → 스케줄러 → 실행