HOWTO · Python

Python 中的定时器函数

本教程演示如何监控和分析 python 代码的运行时间

本页内容

大多数经过时间测量都应使用 time.perf_counter();如果要测量当前进程消耗的 CPU 时间,则使用 time.process_time()。time 模块还提供 time.time(),用于获取系统时钟时间戳;time.monotonic() 则适用于不应受系统时钟调整影响的经过时间测量。每种计时方式都遵循同一模式:记录开始读数,执行待测工作,再记录结束读数,最后用结束读数减去开始读数。以下代码仅用于说明模式;测得的时长会因机器和每次运行而异。

使用 time.time() 测量墙上时钟时间

time.time() 返回当前系统时钟时间,即自 Unix 纪元(1970 年 1 月 1 日 UTC 00:00:00)以来经过的秒数。需要保存、显示时间戳,或将它与另一个时间戳比较时,可以使用此函数。由于它遵循系统时钟,操作系统或用户调整时钟后,读数也可能发生变化。因此,它不适合作为测量短时间间隔的默认选择:两次读数之间若发生时钟调整,计算出的差值就可能失真。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

import time

start = time.time()
total = sum(range(1, 1001))
end = time.time()

print(f"sum={total}")
print(f"elapsed={end - start:.6f} seconds")

第一行输出的是确定的求和结果;第二行是测得的时长,会因运行情况而异。请将要测量的代码放在两次读数之间,这样两者相减所得的时长才对应预期的工作内容。

使用 time.process_time() 测量 CPU 时间

time.process_time() 测量当前进程消耗的 CPU 时间。它不包括休眠、等待输入、等待网络响应或等待其他进程所花的时间。若要估算代码实际占用了多少处理器时间,应使用此函数;若要测量用户等待操作完成的总时长,则应使用经过时间计时方式。用结束读数减去开始读数,就能得到两次读数之间这段工作的 CPU 耗时。

本节中的代码以及显示的标签或输出仍为英文。

import time

start = time.process_time()
total = sum(number * number for number in range(100_000))
cpu_seconds = time.process_time() - start
print(f"sum={total}; CPU time={cpu_seconds:.6f} seconds")

如果任务经常处于等待状态,其 CPU 耗时可能远短于经过时间。这个差值有助于区分计算和等待,但仅凭它无法确定进程具体在等待什么。

使用 time.perf_counter() 测量经过时间

time.perf_counter() 是用于测量经过时间间隔的高分辨率单调时钟。它的起点未指定,因此应使用两次读数之差,不要把单次读数解释为日期或时间戳。与进程 CPU 时间不同,经过时间包括休眠和等待所花的时间。它既适用于短函数,也适用于较长的操作;精度高并不意味着只能用来测量小型进程。

本节中的代码以及显示的标签或输出仍为英文。

import time

start = time.perf_counter()
time.sleep(0.1)
elapsed = time.perf_counter() - start
print(f"elapsed={elapsed:.3f} seconds")

测得的时长通常会接近指定的休眠时长,但调度和系统负载也可能增加耗时。进行基准测试时,应在相近条件下重复测量可比的工作并比较结果,而不要把单次读数当作保证值。

使用 time.monotonic() 测量经过时间

time.monotonic() 同样使用单调时钟测量经过时间;系统时钟更新不会使它倒退。它的参考起点没有定义,因此只有两次读数之差才有意义。当墙上时钟发生变化不应影响计算时,可以用它设置超时截止时间或检查经过的时长。它不会根据外部时钟变化调整读数,而是在测量时间间隔时避开这些变化的影响。

本节中的代码以及显示的标签或输出仍为英文。

import time

start = time.monotonic()
time.sleep(0.1)
elapsed = time.monotonic() - start
print(f"elapsed={elapsed:.3f} seconds")

需要 Unix 时间戳时,选择 time.time();需要测量进程消耗的 CPU 时间时,选择 time.process_time();测量一般的经过时间时,选择 time.perf_counter()。如果时间间隔或超时计算必须不受系统时钟变化影响,则选择 time.monotonic()。无论使用哪种函数,两次读数之间的代码决定了实际测量的工作范围。