Python time.perf_counter_ns 函数
上次修改时间:2025 年 4 月 11 日
本综合指南探讨 Python 的 time.perf_counter_ns
函数,该函数返回以纳秒为单位的高分辨率性能计数器。我们将介绍高精度计时、基准测试和实用示例。
基本定义
time.perf_counter_ns
函数返回一个整数,表示以纳秒为单位的性能计数器。它为短时间测量提供最高可用的分辨率计时器。
主要特征:纳秒分辨率、单调递增(始终增加)、不受系统时钟更改的影响,非常适合基准测试和性能分析。计数器的参考点未定义(只有差异才有意义)。
基本性能测量
time.perf_counter_ns
最简单的用法是以纳秒精度测量代码执行时间。此示例显示了基本用法。
import time def calculate_sum(n): return sum(range(n)) # Start timer start = time.perf_counter_ns() # Execute function result = calculate_sum(1000000) # End timer end = time.perf_counter_ns() # Calculate duration in nanoseconds duration = end - start print(f"Calculation took {duration} ns") print(f"Result: {result}")
此示例演示如何以纳秒精度测量函数的执行时间。持续时间通过从结束时间戳中减去开始时间戳来计算。
请注意,perf_counter_ns 的绝对值没有意义 - 只有测量值之间的差异才有用。
比较 perf_counter_ns 与 perf_counter
此示例将 perf_counter_ns
与其浮点对应项 perf_counter
进行比较,以显示精度差异。
import time def empty_loop(n): for _ in range(n): pass iterations = 1000000 # Using perf_counter (float seconds) start = time.perf_counter() empty_loop(iterations) end = time.perf_counter() float_duration = end - start # Using perf_counter_ns (integer nanoseconds) start_ns = time.perf_counter_ns() empty_loop(iterations) end_ns = time.perf_counter_ns() ns_duration = end_ns - start_ns print(f"perf_counter: {float_duration:.9f} sec") print(f"perf_counter_ns: {ns_duration} ns") print(f"Converted ns: {ns_duration / 1e9:.9f} sec")
perf_counter_ns
提供整数纳秒,而 perf_counter
返回浮点秒。ns 版本避免了非常短的时间间隔的浮点精度问题。
对于大多数计时需求,两者都有效,但 perf_counter_ns 更适合极其精确的测量。
测量函数调用开销
perf_counter_ns
可以测量非常小的时间间隔,例如函数调用开销。此示例演示了此功能。
import time def empty_function(): pass # Measure single call overhead start = time.perf_counter_ns() empty_function() end = time.perf_counter_ns() single_call = end - start # Measure average overhead over many calls trials = 1000000 start = time.perf_counter_ns() for _ in range(trials): empty_function() end = time.perf_counter_ns() avg_call = (end - start) / trials print(f"Single call overhead: {single_call} ns") print(f"Average call overhead: {avg_call:.2f} ns")
这测量了调用空函数所花费的时间。单次调用测量显示了原始开销,而平均版本降低了噪声。
当优化性能关键型代码(每一纳秒都很重要)时,这种精确的测量非常有用。
基准测试不同的实现
此示例使用 perf_counter_ns
来比较相同算法的不同 Python 实现的性能。
import time def sum_with_for(n): total = 0 for i in range(n): total += i return total def sum_with_builtin(n): return sum(range(n)) def measure(func, n, trials=100): start = time.perf_counter_ns() for _ in range(trials): func(n) end = time.perf_counter_ns() return (end - start) / trials n = 10000 trials = 100 for_loop_time = measure(sum_with_for, n, trials) builtin_time = measure(sum_with_builtin, n, trials) print(f"For loop sum: {for_loop_time:.0f} ns per call") print(f"Builtin sum: {builtin_time:.0f} ns per call") print(f"Builtin is {for_loop_time/builtin_time:.1f}x faster")
该示例测量了两种对数字求和的方法:使用手动 for 循环与 Python 的内置 sum。结果显示了它们的相对性能。
多次试验的平均可以减少测量噪声,并提供更可靠的实现之间的比较。
精度限制和时钟分辨率
此示例通过测量最小可检测间隔来演示 perf_counter_ns
的实际分辨率限制。
import time def measure_resolution(): # Measure smallest detectable time difference min_diff = float('inf') for _ in range(1000): t1 = time.perf_counter_ns() t2 = time.perf_counter_ns() if t2 > t1: diff = t2 - t1 if diff < min_diff: min_diff = diff return min_diff resolution = measure_resolution() print(f"Smallest detectable interval: {resolution} ns") # Verify with time.sleep(0) sleep_start = time.perf_counter_ns() time.sleep(0) sleep_end = time.perf_counter_ns() print(f"time.sleep(0) duration: {sleep_end - sleep_start} ns")
第一部分测量计时器可以检测到的最小时间差。第二部分表明,即使 sleep(0) 也需要可测量的时间,因为 Python 的开销。
实际分辨率取决于硬件和操作系统。现代系统通常具有纳秒分辨率计时器,但开销可能会限制实际使用。
使用 perf_counter_ns 进行微基准测试
此示例演示如何使用 perf_counter_ns
创建微基准装饰器,以实现精确的函数计时。
import time from functools import wraps def benchmark(n_trials=1000, warmup=100): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): # Warmup phase (avoid JIT/cache effects) for _ in range(warmup): func(*args, **kwargs) # Measurement phase total_ns = 0 for _ in range(n_trials): start = time.perf_counter_ns() func(*args, **kwargs) end = time.perf_counter_ns() total_ns += (end - start) avg_ns = total_ns / n_trials print(f"{func.__name__}: {avg_ns:.1f} ns per call " f"(over {n_trials} trials)") return func(*args, **kwargs) return wrapper return decorator @benchmark(n_trials=10000, warmup=1000) def list_comprehension(n): return [i*i for i in range(n)] @benchmark(n_trials=10000, warmup=1000) def manual_loop(n): result = [] for i in range(n): result.append(i*i) return result list_comprehension(100) manual_loop(100)
该装饰器处理预热运行以避免启动影响,然后测量多次试验的平均执行时间。这提供了可靠的微基准。
该示例比较了列表推导与手动循环性能,展示了如何正确地对小的代码差异进行基准测试。
最佳实践
- 精度需求: 使用 perf_counter_ns 进行纳秒级精度计时
- 单调性: 计数器始终增加,非常适合用于测量时间间隔
- 平均: 对于小型操作,在多次运行中取平均值
- 预热: 包括预热运行以避免启动开销
- 时钟分辨率: 注意系统的实际计时器分辨率
资料来源
作者
列出所有 Python 教程。