Python 타임아웃이 시스템 시각 변경에 흔들릴 때 monotonic_ns 쓰기
Python monotonic_ns로 전체 타임아웃을 계산한다. 시스템 시각 보정이 잔여 시간에 미치는 영향을 재현하고 재시도와 절전의 적용 범위를 살펴본다.
Python 서비스에서 시스템 시각을 바꾼 뒤 요청이 너무 빨리 취소되거나 오래 기다린다면, 타임아웃 계산에 time.time()을 쓰는지 확인한다. 프로세스에서 소비한 시간에 상한을 두려면 time.monotonic_ns()로 시작 시점에 마감값을 한 번 계산하고, 각 단계에서 남은 시간을 다시 구한다. 아래 예제로 시계가 앞뒤로 보정되어도 전체 요청에 배정한 시간이 유지되는지 확인한다.
시각 보정이 표시된 시계와 일정하게 진행하는 시계를 나란히 그린 일러스트
벽시계로 계산한 잔여 시간이 바뀌는 이유
time.time()은 달력 시각과 대응하는 초를 반환한다. 운영체제의 시각이 바뀌면 연속된 두 호출의 차이에는 실제로 기다린 시간과 시각 보정이 함께 반영될 수 있다. 예를 들어 5초 제한에서 2초가 지난 뒤 벽시계가 30초 뒤로 이동하면 벽시계 기준 잔여 시간은 33초가 된다. 30초 앞으로 이동하면 이미 만료된 것으로 계산된다.
time.monotonic_ns()는 뒤로 가지 않는 시계의 값을 정수 나노초로 반환한다. 기준점은 정의되어 있지 않으므로 같은 시계에서 얻은 두 값의 차이를 사용한다. 날짜나 만료 시각을 기록할 때는 벽시각을 쓰고, 진행 중인 작업의 잔여 시간을 계산할 때는 단조 시계를 사용한다. Python time 문서
전체 마감값을 한 번 계산하기
deadline = monotonic_ns() + budget_ns로 마감값을 만든다. 각 시도 전 remaining_ns(deadline)을 다시 계산하고, 값이 0이면 다음 시도는 시작하지 않는다. 초 단위 타임아웃을 받는 API에는 양수 잔여 시간을 1_000_000_000으로 나눠 넘긴다. 재시도 사이에 대기하는 경우에도 남은 시간 내에서 기다린 뒤 잔여 시간을 다시 확인한다. 매 시도마다 전체 제한을 다시 부여하면 총 소요 시간은 의도한 상한을 넘을 수 있다.
아래 코드를 monotonic_deadline.py로 저장하고 python3 monotonic_deadline.py를 실행한다. 시각 보정은 테스트용 시계에서 모의했다.
시계가 앞뒤로 이동할 때 확인하기
2026년 11월 14일 Linux의 Python 3.12.14에서 실행했다. 시각을 30초 앞뒤로 바꾼 사례 모두에서 단조 시계 기준 잔여 시간이 3초였다. 추가 시간이 지나면 잔여 시간이 0이 되는지와 실제 monotonic_ns()에서 얻은 현재값을 마감값으로 사용했을 때도 0이 반환되는지 확인했다.
마감값의 범위와 절전 처리
단조 시계에서 얻은 마감값은 같은 시계로 계산하는 동안 사용한다. 다른 호스트에 보내야 한다면 프로토콜에서 정한 남은 시간이나 절대 만료 시각을 전달한다. 수신 측에서 시간 예산을 새로 잡을 때는 전송에 걸린 시간과 호스트 간 시계 차이를 어떤 방식으로 처리할지 정한다.
Linux의 CLOCK_MONOTONIC은 벽시각의 불연속적인 변경에 영향을 받지 않지만, 점진적인 시계 보정의 영향을 받을 수 있고 시스템 절전 시간은 세지 않는다. 절전 시간을 포함해야 하는 Linux 작업에는 CLOCK_BOOTTIME이 해당 요건을 충족한다. 현재 Python 프로세스가 사용하는 시계는 time.get_clock_info("monotonic")으로 확인할 수 있다. 이 예제는 시각 보정의 효과를 모의 검증했으며 실제 절전과 네트워크 API별 타임아웃은 검증 범위 밖이다. Linux clock_gettime(2) · Python time 문서
English version ·
Use Python monotonic_ns for Timeouts That Survive Wall Clock Changes