Python time.monotonic 函数
上次修改时间:2025 年 4 月 11 日
本综合指南探讨了 Python 的 time.monotonic 函数,该函数提供了一个单调时钟,用于可靠的时间测量。我们将介绍其在基准测试、性能计时和实际示例中的用法。
基本定义
time.monotonic 函数返回一个浮点数,表示自未指定起始点以来的秒数。 关键特性是它永远不会向后,即使系统时间被调整。
主要特点:保证单调(永不递减),不受系统时钟更改的影响,是测量经过时间的理想选择,并且具有未指定的参考点(只有差异才重要)。 分辨率取决于平台。
time.monotonic 的基本用法
time.monotonic 最简单的用法是测量两点之间经过的时间。 此示例显示了基本计时功能。
import time
# Get initial monotonic time
start = time.monotonic()
# Simulate some work
time.sleep(1.5)
# Get end time
end = time.monotonic()
# Calculate elapsed time
elapsed = end - start
print(f"Elapsed time: {elapsed:.3f} seconds")
此示例演示了测量经过时间的基本模式。 两个单调时间戳之间的差异给出了可靠的持续时间。
:.3f 格式说明符以毫秒精度显示时间,但实际精度取决于平台。
比较 time.monotonic 和 time.time
此示例将 time.monotonic 与 time.time 进行比较,以显示系统时钟更改如何以不同的方式影响它们。
import time
print("Starting comparison...")
print("Change your system clock during this test to see the difference")
start_mono = time.monotonic()
start_time = time.time()
time.sleep(10) # Change system clock during this sleep
end_mono = time.monotonic()
end_time = time.time()
print(f"monotonic duration: {end_mono - start_mono:.2f} seconds")
print(f"time.time duration: {end_time - start_time:.2f} seconds")
time.monotonic 将始终显示 ~10 秒,而如果时钟被调整,time.time 可能会显示不正确的持续时间。
这说明了为什么单调时钟对于可靠的计时测量至关重要,尤其是对于长时间运行的进程。
使用 time.monotonic 进行精确基准测试
由于其高分辨率,time.monotonic 非常适合微基准测试。 此示例测量函数的执行时间。
import time
def calculate_primes(n):
primes = []
for candidate in range(2, n + 1):
is_prime = True
for divisor in range(2, int(candidate ** 0.5) + 1):
if candidate % divisor == 0:
is_prime = False
break
if is_prime:
primes.append(candidate)
return primes
# Time the function
start = time.monotonic()
primes = calculate_primes(10000)
end = time.monotonic()
print(f"Found {len(primes)} primes in {end - start:.6f} seconds")
此模式对于性能优化很有用。 单调时钟提供可靠的计时,不受系统时钟调整的影响。
为了获得更高的精度,请考虑 time.perf_counter,它可能在某些平台上提供更好的分辨率。
创建计时器类
此示例显示了如何使用 time.monotonic 创建可重用的计时器类以进行精确的计时测量。
import time
class Timer:
def __init__(self):
self._start = None
self._elapsed = 0
def start(self):
if self._start is not None:
raise RuntimeError("Timer already running")
self._start = time.monotonic()
def stop(self):
if self._start is None:
raise RuntimeError("Timer not running")
self._elapsed += time.monotonic() - self._start
self._start = None
def reset(self):
self._start = None
self._elapsed = 0
@property
def elapsed(self):
if self._start is not None:
return self._elapsed + (time.monotonic() - self._start)
return self._elapsed
# Usage example
timer = Timer()
timer.start()
time.sleep(1.5)
timer.stop()
print(f"Elapsed: {timer.elapsed:.3f} seconds")
timer.start()
time.sleep(0.75)
timer.stop()
print(f"Total elapsed: {timer.elapsed:.3f} seconds")
计时器类可以启动、停止和查询经过的时间。 它累积多个启动/停止周期的时间。
这对于分析需要在多个执行中进行累积计时的代码段很有用。
使用 time.monotonic 实现超时
此示例显示了如何使用 time.monotonic 实现超时机制,该机制不会受到系统时钟更改的影响。
import time
def run_with_timeout(timeout_seconds, func, *args, **kwargs):
start = time.monotonic()
result = func(*args, **kwargs)
elapsed = time.monotonic() - start
if elapsed > timeout_seconds:
raise TimeoutError(f"Operation timed out after {elapsed:.2f} seconds")
return result
# Example usage
def long_running_operation(duration):
time.sleep(duration)
return "Done"
try:
# This will succeed
print(run_with_timeout(2, long_running_operation, 1.5))
# This will timeout
print(run_with_timeout(1, long_running_operation, 1.5))
except TimeoutError as e:
print(f"Error: {e}")
超时是可靠的,因为它使用单调时钟。 即使在执行期间系统时钟发生变化,超时也能正常工作。
请注意,这实际上不会中断该函数 - 它只会在完成后检查时间。 对于真正的中断,请考虑使用线程。
测量游戏循环中的帧速率
此示例演示了如何使用 time.monotonic 来测量和保持游戏循环中一致的帧速率。
import time
TARGET_FPS = 60
FRAME_TIME = 1.0 / TARGET_FPS
def game_loop():
frame_count = 0
start_time = time.monotonic()
last_frame_time = start_time
while frame_count < 120: # Run for 120 frames
current_time = time.monotonic()
elapsed = current_time - last_frame_time
# Only process frame if enough time has passed
if elapsed >= FRAME_TIME:
# Simulate game logic and rendering
time.sleep(0.005) # Simulate variable work time
frame_count += 1
last_frame_time = current_time
# Calculate current FPS
total_elapsed = current_time - start_time
current_fps = frame_count / total_elapsed
print(f"Frame {frame_count}: {current_fps:.1f} FPS")
game_loop()
游戏循环使用单调时钟来保持一致的计时,而不管系统时钟如何变化。 它计算实际达到的 FPS。
这种模式对于游戏和模拟至关重要,在这些游戏和模拟中,一致的计时比挂钟时间更重要。
最佳实践
- 用于持续时间: 始终用于测量经过的时间,而不是绝对时间
- 参考点: 零点是任意的 - 只有差异才重要
- 高精度: 对于微基准测试,请考虑 time.perf_counter
- 平台一致性: 分辨率因平台而异
- 长时间运行的进程: 对于长时间运行的进程中的可靠计时至关重要
资料来源
作者
列出所有 Python 教程。