Python time.monotonic_ns 函数
上次修改时间:2025 年 4 月 11 日
本综合指南探讨了 Python 的 time.monotonic_ns 函数,该函数返回一个纳秒级分辨率的单调时钟值。我们将介绍精确计时、性能测量和实际示例。
基本定义
time.monotonic_ns 函数以纳秒为单位返回一个时钟值。它是单调的(永不减少)并且不受系统时钟调整的影响。
主要特点:纳秒级分辨率,非常适合精确的计时间隔,并保证永远不会倒退。参考点未定义,但在程序执行期间是一致的。
monotonic_ns 的基本用法
此示例演示了 time.monotonic_ns 的基本用法,用于测量具有纳秒精度的计时间隔。
import time
# Get current monotonic time in nanoseconds
start = time.monotonic_ns()
# Simulate some work
time.sleep(0.5) # Sleep for 500 milliseconds
# Get end time
end = time.monotonic_ns()
# Calculate duration in nanoseconds
duration_ns = end - start
duration_ms = duration_ns / 1_000_000 # Convert to milliseconds
print(f"Operation took {duration_ns} nanoseconds")
print(f"Which is {duration_ms:.2f} milliseconds")
此示例展示了如何以纳秒精度测量时间间隔。即使系统时钟发生变化,睡眠持续时间也能被准确测量。
请注意,虽然分辨率为纳秒,但实际精度取决于底层系统能力。
比较 monotonic_ns 和 monotonic
此示例将 time.monotonic_ns 与 time.monotonic 进行比较,以显示精度和表示形式的差异。
import time
def test_function():
sum(range(1_000_000))
# Using time.monotonic()
start = time.monotonic()
test_function()
end = time.monotonic()
print(f"time.monotonic(): {(end - start) * 1e9:.0f} ns")
# Using time.monotonic_ns()
start = time.monotonic_ns()
test_function()
end = time.monotonic_ns()
print(f"time.monotonic_ns(): {end - start} ns")
这两个函数使用相同的底层时钟,但 monotonic_ns 提供对纳秒值的直接访问,无需浮点转换。
对于非常精确的测量,monotonic_ns 版本避免了潜在的浮点精度问题。
使用 monotonic_ns 进行微基准测试
此示例演示了如何使用 time.monotonic_ns 对具有高精度的小代码段进行微基准测试。
import time
def benchmark(func, iterations=1_000_000):
start = time.monotonic_ns()
for _ in range(iterations):
func()
end = time.monotonic_ns()
ns_per_op = (end - start) / iterations
print(f"{func.__name__}: {ns_per_op:.2f} ns/operation")
def empty_function():
pass
def simple_math():
42 * 42
benchmark(empty_function)
benchmark(simple_math)
此模式对于测量非常小的操作的性能非常有用。纳秒分辨率允许对单个操作进行精确计时。
请注意,微基准测试可能会受到各种系统因素的影响,应谨慎解释。
精确的速率限制
此示例使用 time.monotonic_ns 实现了一个高精度速率限制器,以纳秒级的精度控制操作频率。
import time
class NanoRateLimiter:
def __init__(self, operations_per_second):
self.interval_ns = 1_000_000_000 // operations_per_second
self.last_run = 0
def __call__(self, func):
def wrapper(*args, **kwargs):
now = time.monotonic_ns()
elapsed = now - self.last_run
if elapsed < self.interval_ns:
delay_ns = self.interval_ns - elapsed
time.sleep(delay_ns / 1e9) # Convert to seconds
self.last_run = time.monotonic_ns()
return func(*args, **kwargs)
return wrapper
@NanoRateLimiter(1000) # 1000 operations per second
def high_freq_operation():
print("Operation at", time.monotonic_ns() % 1_000_000)
for _ in range(5):
high_freq_operation()
速率限制器通过精确测量纳秒级的时间间隔,确保操作不会超过指定的速率。
这对于硬件控制或高频 API 尤其有用,在这些情况下,精确计时至关重要。
测量小代码块
此示例展示了如何使用 time.monotonic_ns 和上下文管理器来方便地测量非常小的代码块。
import time
from contextlib import contextmanager
@contextmanager
def time_ns():
start = time.monotonic_ns()
yield
end = time.monotonic_ns()
print(f"Duration: {end - start} ns")
# Measure list comprehension
with time_ns():
squares = [x*x for x in range(1000)]
# Measure dictionary creation
with time_ns():
d = {x: x*x for x in range(1000)}
上下文管理器自动测量并打印 with 语句中代码块的执行时间。
这种模式可以很容易地将精确计时添加到现有代码中,而不会用计时代码使逻辑混乱。
长时间运行的进程监控
此示例演示了如何使用 time.monotonic_ns 来监控长时间运行的进程,并定期更新进度。
import time
def long_running_task():
total_items = 1_000_000
start_time = time.monotonic_ns()
last_report = start_time
for i in range(total_items):
# Simulate work
time.sleep(0.001)
# Report progress every second
current_time = time.monotonic_ns()
if current_time - last_report >= 1_000_000_000:
elapsed_s = (current_time - start_time) / 1_000_000_000
progress = (i + 1) / total_items * 100
print(f"{elapsed_s:.1f}s: {progress:.1f}% complete")
last_report = current_time
total_time = (time.monotonic_ns() - start_time) / 1_000_000_000
print(f"Task completed in {total_time:.2f} seconds")
long_running_task()
该示例使用纳秒级计时来精确控制进度报告的时间间隔,同时避免浮点累积误差造成的漂移。
这种方法确保即使对于非常长时间运行的进程,计时也是准确的,因为很小的计时误差可能会累积得非常显著。
最佳实践
- 精度需求: 当需要纳秒分辨率时,使用 monotonic_ns
- 长时间持续: 请注意长时间测量可能导致整数溢出
- 系统限制: 实际精度取决于操作系统和硬件
- 时钟源: 使用系统上可用的最佳单调时钟
- 转换: 需要时,除以 1e9 得到秒数
资料来源
作者
列出所有 Python 教程。