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 教程。