跳到正文
效率工具实用笔记关于本站
效率工具

测量一段操作耗时:perf_counter与日历时间区别

约 7 分钟阅读AI 辅助整理

perf_counter 是最高可用分辨率的性能计数器,参考点未定义,只能取两次调用的差值;time.time() 返回自 epoch 起的秒数,可被系统调回。测一段操作耗时用 perf_counter 差值,记录“某件事发生在什么时候”用 time()。

本文要点

  1. 下面这段只在你自己的练习目录里运行,不读写外部文件、不改系统设置

  2. 也就是说,用 time() 量耗时,结果可能因为系统对时、手动改时间等原因出现负值或偏大偏小

  3. 如果你的自建操作里有 time.sleep(),要分清两个计时器

测量一段操作耗时:perf_counter与日历时间区别的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

先分清你要的是“持续多久”还是“几点发生”

如果你只是想量一段自建操作花了多长时间,用 time.perf_counter() 取两次调用的差值就够了。

按 Python 官方 time 模块文档,perf_counter() 返回一个性能计数器的值,单位是秒的小数部分,是“可用来测量短时长的最高可用分辨率时钟”。文档同时写明:它返回值的参考点是未定义的,所以只有两次调用结果之间的差值有意义。

而 time.time() 返回的是自 epoch 起的秒数,是一个浮点数。文档说明 epoch 是时间开始计数的那个点,即 time.gmtime(0) 的返回值,在所有平台上都是 1970 年 1 月 1 日 00:00:00 UTC。

这两句话决定了用途分工:perf_counter 的绝对值没有意义,只能做减法;time() 的绝对值有意义,可以换算成年月日时分秒。所以“这段操作花了多久”用前者,“这件事发生在哪一刻”用后者。

本文只演示计时器差值的简单无副作用计算,不给出任何性能基准结论,也不把示例值当成真实测量结果。

用自建脚本量一段空转:两次 perf_counter 相减

下面这段只在你自己的练习目录里运行,不读写外部文件、不改系统设置。路径请换成你自己的练习相对路径,例如 exercise/。

import time

start = time.perf_counter()

# 这里放你要量的那段操作,下面用一个自建的循环占位
total = 0
for i in range(100000):
    total += i

end = time.perf_counter()
print("elapsed:", end - start)

输入:一段你自己写的、没有副作用的计算。输出:一个浮点数,表示两次调用之间经过的秒数。

关键点是只取差值。start 和 end 各自的数值在不同机器、不同运行之间都不一样,打印它们本身没有比较意义。文档说得很清楚:参考点未定义,只有差值有效。

如果你需要更细的粒度,文档提供了 perf_counter_ns(),它返回整数纳秒,用来避免浮点类型带来的精度损失。用法一样,也是两次相减。

为什么不用 time.time() 量耗时:它可能被调回去

time.time() 也能做减法,但文档专门提示了一个风险:虽然这个函数通常返回非递减的值,但如果系统时钟在两次调用之间被调回,它可能返回比上一次更小的值。

也就是说,用 time() 量耗时,结果可能因为系统对时、手动改时间等原因出现负值或偏大偏小。而 perf_counter 在 CPython 上使用的是与 time.monotonic() 相同的时钟,文档描述 monotonic 是一个“不能倒退的时钟”,且不受系统时钟更新的影响。

所以判断标准可以简化成一句:

- 要量“经过了多少时间”,且不希望被系统时钟调整干扰,用 perf_counter。

- 要记录“这个时刻对应的日历时间”,用 time(),必要时再用 gmtime() 或 localtime() 换算。

文档还提到,time() 返回的数值可以传给 gmtime() 得到 UTC 的 struct_time,或传给 localtime() 得到本地时间的 struct_time。这是 time() 的用途,不是 perf_counter 的用途。

perf_counter 包含 sleep 时间,process_time 不包含

如果你的自建操作里有 time.sleep(),要分清两个计时器。

文档对 perf_counter 的说明是:它包含 sleep 期间经过的时间。对 process_time 的说明则相反:它返回当前进程的系统 CPU 时间与用户 CPU 时间之和,不包含 sleep 期间经过的时间。

这意味着同一个脚本,用两个计时器量出来的差值回答的是不同问题:

- perf_counter 差值:从开始到结束,墙上过了多久。

- process_time 差值:这段时间里,CPU 真正花在这个进程上多少。

文档对 process_time 也写明参考点未定义,只有两次调用的差值有效,并且它是进程范围的。所以两者都不能拿绝对值去比较,只能各自做减法。

选择方法:你关心“用户等了多久”,用 perf_counter;你关心“CPU 忙了多久”,用 process_time。本文只演示差值计算,不对任何具体数值下结论。

检查结果时先看三件事,再决定要不要重测

拿到一个差值后,不要直接把它当成这段操作的固有耗时。可以按下面顺序检查(以下为编辑整理的检查方向,不是对某台机器的实测记录):

1. 差值是不是负数。如果是,说明你用的很可能是 time() 而不是 perf_counter,或者两次调用的顺序写反了。

2. 差值是不是明显偏大。检查这段操作里有没有包含 sleep、等待输入、网络请求这类会拉长时间的动作。perf_counter 会把 sleep 算进去。

3. 两次调用之间有没有夹进无关代码。把 start 和 end 尽量贴近你要量的那段操作,中间不要放打印、文件读写等额外动作。

文档还提醒了一点:各种实时函数的精度可能低于其数值单位所暗示的精度。例如在多数 Unix 系统上,时钟每秒只“滴答”50 或 100 次。所以差值的小数位多,不代表精度就有那么高。

如果同一段操作量了多次,各次结果不一致是正常的,不要取其中最小的那个当成“真实耗时”。

适用限制与参考资料

适用范围:本文只处理用 perf_counter 和 time() 的差值测量一段自建操作的耗时,以及两者的用途区别。所有示例都是自建的练习代码,不涉及真实业务数据,也不执行任何系统修改。

几条需要提前知道的边界:

- 文档说明,这个模块的函数并非在所有平台上都可用,多数函数调用的是同名平台 C 库函数,语义可能因平台而异。

- 本文不给出任何性能基准、耗时标准或“多快算快”的判断,示例中的循环次数和打印结果都不是基准结论。

- 本文不涉及多线程、多进程计时,也不涉及 clock_gettime 等底层接口。

- 计时结果受机器负载、解释器版本等因素影响,本文不对具体数值做解释。

参考资料:Python 官方 time 模块文档,https://docs.python.org/3/library/time.html

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回效率工具 →