入门
本页将指导您如何使用 Stopwatch 来计算程序的运行时间。

指导

当我们尝试计算一段程序的运行时间时,通常会使用 timeit 模块中定义的 default_timer 函数。
1
current_timer_count: float = float(timeit.default_timer())
2
time.sleep(3)
3
print(float(timeit.default_timer()) - current_timer_count)
Copied!
但在一些项目中,我们可能需要统计各个阶段的运行时间并统一管理和维护。此时,上文示例代码中演示的计算方式将非常不便。当需要计算的阶段节点过多时,将会产生大量重复的代码,造成代码冗余且不利于维护。
对于 Python 入门开发者而言,上文示例代码中演示的计算方式可能不利于理解。
在下文中,我们通过几段连续的 Python 代码片段来向您演示如何使用 Stopwatch 计算程序的运行时间。

导入模块

为便于理解,我们需要使用 time 模块中的 sleep 函数来模拟程序的运行流程。
1
import time
Copied!
在使用 Stopwatch 之前,我们应该导入 Stopwatch
1
from stopwatch import Stopwatch
Copied!
如果您需要捕获 Stopwatch 的相关异常,应该导入:
1
from stopwatch import StatusError
2
from stopwatch import LapNameError
Copied!

创建 Stopwatch

Stopwatch 的功能被定义在名为 Stopwatch 的类中。因此,我们可以通过实例化 Stopwatch 类来创建一个或多个 Stopwatch 实例。
1
demo_stopwatch: Stopwatch = Stopwatch(
2
default_precision = None
3
)
Copied!
Stopwatch 的构造器方法包含一个数据类型为 int 的可选参数 default_precision,该参数指示被创建的 Stopwatch 实例的计时器精度(小数点位数)。如果未提供该参数或值为 None,则该参数的默认值为 3

开始 Stopwatch

在上文中,我们定义了名为 demo_stopwatch 的变量,它是一个 Stopwatch 实例。现在我们尝试使 demo_stopwatch 开始计时。
1
demo_stopwatch.start()
Copied!
接着,我们使用 time.sleep 函数挂起当前线程 3 秒,模拟第一阶段的程序代码运行。
1
time.sleep(3)
Copied!

记录 Stopwatch

当我们的项目中存在多个程序阶段时,为了计算每个阶段的运行时间,阶段性计时是必不可少的。在上文示例代码中我们使用 time.sleep 函数模拟程序运行的第一个阶段,接着我们使用 lap 方法记录一次计时结果。
1
lap_of_watch: float = demo_stopwatch.lap(
2
lap_name = 'stage1'
3
)
Copied!
计时记录分为 2 种:
  • 命名计时记录
  • 匿名计时记录
方法 lap 具有一个数据类型为 str 的可选参数 lap_name,该参数指示计时记录的唯一名称。如果未提供该参数或值为 None,则计时记录是匿名的。
该方法返回数据类型为 float 的返回值,其指示当前阶段的计时结果。如果这是第一条计时记录,计时结果是从 Stopwatch 开始计时到目前的间隔时间(秒);否则,计时结果是从上一条计时记录到目前的间隔时间(秒)。
请注意,计时记录的名称在当前 Stopwatch 实例中必须是唯一的,即不可重复。否则,将引发 LapNameError 异常。
接着,我们再次使用 time.sleep 函数挂起当前线程 1 秒,模拟第二阶段的程序代码运行。
1
time.sleep(1)
Copied!
然后,记录第二阶段的计时结果。
1
lap_of_watch: float = demo_stopwatch.lap(
2
lap_name = 'stage2'
3
)
Copied!

停止 Stopwatch

在上文中,我们使用 time.sleep 函数模拟了程序运行的第一阶段和第二阶段,并使用 lap 方法记录了程序运行第一阶段和第二阶段的计时结果。
现在,我们使 demo_stopwatch 停止计时。
1
total_of_watch: float = demo_stopwatch.stop()
Copied!
方法 stop 返回数据类型为 float 的返回值,其指示当前 Stopwatch 实例从首次开始计时到停止计时的总计时时间(秒)。
该返回值可以被忽略,我们可以使用 get_watch 方法即时检查 Stopwatch 实例的总计时时间:
1
total_of_watch: float = demo_stopwatch.get_watch(
2
watch_precision: int = None
3
)
Copied!
方法 get_watch 有一个数据类型为 int 的可选参数,该参数指示获取的总计时精度(小数点)。如果未提供该参数或值为 None,该参数的默认值为 Stopwatch 类构造器方法参数 default_precision 的值。
请注意,在低于 0.1.3 版本的 Stopwatch 中使用 get_watch 方法时,应该确保 Stopwatch 实例已经停止计时,否则将引发 StatusError 异常。
我们可以使用 get_status 方法检查当前 Stopwatch 实例的状态。
1
if demo_stopwatch.get_status() == StopwatchStatus.Stopped:
2
print('stopwatch has stopped timing')
Copied!
StopwatchStatus 是预定义的 Stopwatch 状态枚举器,可以与方法 get_status 的返回值比较。
1
from stopwatch import StopwatchStatus
Copied!

获取 Stopwatch 记录

在上文中,我们使用 lap 方法分阶段记录了程序运行第一阶段和第二阶段的计时结果。现在我们尝试获取这些计时记录。

获取命名计时记录

我们可以使用 get_lap 方法获取命名的计时记录。
1
lap_of_watch: float = demo_stopwatch.get_lap(
2
lap_name = 'stage1',
3
lap_precision = 3
4
)
Copied!
方法 get_lap 有 2 个参数,它们分别是:
参数名
数据类型
可选
描述
lap_name
str
False
计时记录的唯一名称。
lap_precision
int
True
获取的计时记录精度(小数点位数)
参数 lap_precision 是可选的。如果未提供该参数或值为 None,该参数的默认值为 Stopwatch 类构造器方法参数 default_precision 的值。
请注意,如果指定计时记录名称不存在,将引发 LapNameError 异常。
如果我们需要确定一个计时记录是否存在,可以使用 has_lap 方法检查。
1
if not demo_stopwatch.has_lap(
2
lap_name = 'stage1'
3
):
4
print('no such lap')
Copied!

获取匿名计时记录

值得注意的是,匿名计时记录并非是真正的匿名,而是使用 lap_ 和记录编号组合的方式来命名计时记录(例如:lap_1)。因此,我们也可以使用 get_lap 方法获取匿名计时记录,但更便捷的方式是使用 get_lap_by_number 方法。
1
lap_of_watch: float = demo_stopwatch.get_lap_by_number(
2
lap_number = 1,
3
lap_precision = 3
4
)
Copied!
与方法 get_lap 不同之处是,该方法的参数 lap_number 指示匿名记录的编号(从 1 开始),其数据类型为 int。在该方法内部仍然调用 get_lap 方法获取匿名计时记录。
请注意,如果使用该方法获取非匿名计时记录,将引发 LapNameError 异常。
为使您更加清晰的了解命名计时记录与匿名计时记录之间的关系,我们将通过下文的演示来详细说明。
1
demo_stopwatch.lap('stage1')
2
demo_stopwatch.lap()
3
demo_stopwatch.get_lap_by_number(1)
Copied!
在上文示例代码中,我们记录了 2 次 Stopwatch 当前计时结果,命名计时记录和匿名计时记录各一条。现在 Stopwatch 实例中计时记录集的内容如下:
1
[
2
'stage1',
3
'lap_2'
4
]
Copied!
而在上文示例代码中,使用 get_lap_by_number 方法获取第一条命名计时记录时将引发异常:
1
LapNameError(no such lap: lap_1)
Copied!
因为当前 Stopwatch 实例的计时记录集中不存在名为 lap_1 的命名计时记录,所以必然引发 LapNameError 异常。由此可见匿名计时记录仅是以默认形式(lap_ 和记录编号的组合)对记录命名。

获取所有计时记录的平均结果

如果我们需要获取当前 Stopwatch 实例中所有计时记录的平均计时结果,可以使用 get_average_of_laps 方法。
1
average_of_laps: float = demo_stopwatch.get_average_of_laps(
2
average_precision = None
3
)
Copied!
方法 get_average_of_laps 有一个数据类型为 int 的可选参数 average_precision,该参数指示获取的计时记录平均结果的精度(小数点位数)。如果未提供该参数或值为 None,该方法的行为与 get_lap 一致。

枚举所有计时记录名称

我们还可以使用 get_laps 方法枚举所有计时记录的唯一名称,其中也包含匿名计时记录。
1
for lap_name in demo_stopwatch.get_laps():
2
print(lap_name)
Copied!
方法 get_laps 返回数据类型为 list 的返回值,其中包含所有计时记录的唯一名称,成员数据类型为 str

获取计时记录条数

我们可以使用 get_lap_count 方法获取当前 Stopwatch 实例的计时记录总条数。
1
number_of_laps: int = demo_stopwatch.get_lap_count()
Copied!

重置 Stopwatch

每个 Stopwatch 实例自开始计时起,都会产生当前实例的状态数据(例如:计时记录等...)。如果我们需要清空这些数据,则应该将 Stopwatch 实例重置为初始状态。
Tips: Stopwatch 实例可以重复开始和结束,计时记录和总计时时长都将累计,直到被重置。
1
demo_stopwatch.reset()
Copied!
重置 Stopwatch 实例后,所有状态数据将被清理,Stopwatch 实例重置为初始状态。
请注意,如果 Stopwatch 实例仍然处于计时状态,将引发 StatusError 异常。可以使用 get_status 方法检查 Stopwatch 实例的状态。

示例

下文将以完整的 Python 示例代码演示如何使用 Stopwatch。

源代码

quickstart.py
1
# quickstart.py is python-3.7.4 source file
2
3
import time
4
5
from stopwatch import Stopwatch
6
from stopwatch import StopwatchStatus
7
8
9
# define main function
10
11
def main():
12
13
# instantiate stopwatch
14
15
demo_stopwatch: Stopwatch = Stopwatch(
16
default_precision = 3 # ignorable
17
)
18
19
# make stopwatch start timing
20
21
demo_stopwatch.start()
22
23
# the first stage of the simulation program
24
25
time.sleep(3)
26
27
# it takes time to record the first phase of the program
28
29
demo_stopwatch.lap('stage1')
30
31
# the second stage of the simulation program
32
33
time.sleep(1)
34
35
# it takes time to record the second phase of the program
36
37
demo_stopwatch.lap('stage2')
38
39
# try checking the stopwatch total time every 1 second
40
41
for count in range(3):
42
print('{COUNT} check: {WATCH_SECONDS} seconds'.format(
43
COUNT = count + 1,
44
WATCH_SECONDS = demo_stopwatch.get_watch()
45
))
46
47
# record cycle check time spent on stopwatch
48
49
demo_stopwatch.lap('stage3')
50
51
# get the status of stopwatch
52
53
if demo_stopwatch.get_status() == StopwatchStatus.Started:
54
print('stopwatch is timing...')
55
56
# stop and print the timing of the stopwatch
57
58
print(
59
(
60
'total: {TOTAL_SECONDS} seconds\n'
61
'stage1: {STAGE1_SECONDS} seconds\n'
62
'stage2: {STAGE2_SECONDS} seconds\n'
63
'stage3: {STAGE3_SECONDS} seconds\n'
64
'----------\n'
65
'average of stages: {AVERAGE_SECONDS} seconds'
66
).format(
67
TOTAL_SECONDS = demo_stopwatch.stop(),
68
STAGE1_SECONDS = demo_stopwatch.get_lap('stage1'),
69
STAGE2_SECONDS = demo_stopwatch.get_lap('stage2'),
70
STAGE3_SECONDS = demo_stopwatch.get_lap('stage2'),
71
AVERAGE_SECONDS = demo_stopwatch.get_average_of_laps()
72
)
73
)
74
75
# reset stopwatch
76
77
demo_stopwatch.reset()
78
79
80
# define virtual main function
81
82
if __name__ == '__main__':
83
main()
Copied!

运行结果

1
1 check: 4.001 seconds
2
2 check: 4.002 seconds
3
3 check: 4.003 seconds
4
stopwatch is timing...
5
total: 4.006 seconds
6
stage1: 3.0 seconds
7
stage2: 1.001 seconds
8
stage3: 1.001 seconds
9
----------
10
average of stages: 1.335 seconds
Copied!