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