Python高性能编程(第2版)
上QQ阅读APP看书,第一时间看更新

2.5 使用UNIX命令time的简单计时

我们暂时离开Python,在类UNIX系统上使用一个标准的系统工具。下面的命令呈现有关程序执行时间的各种视图,但不关心程序的内部结构:

$ /usr/bin/time -p python julia1_nopil.py
Length of x: 1000
Total elements: 1000000
calculate_z_serial_purepython took 8.279886722564697 seconds
real 8.84
user 8.73
sys 0.10

注意,这里指定的是/usr/bin/time而不是time,因此执行的是系统命令time,而不是shell内置的版本,后者更简单,用处也没那么大。如果执行命令time --verbose出错,很可能是因为你指定的是shell内置命令time,而不是系统命令time。

通过使用标志-p,得到了3个结果。

real指的是总耗时。

user指的是目标任务占用的CPU时间,但不包括内核函数占用的时间。

sys指的是内核函数占用的CPU时间。

通过将user和sys值相加,可大致知道占用的CPU时间。这个相加结果与real的差值可能是I/O等待时间,也可能表明系统忙于执行其他任务,因此扭曲了测量结果。

time很有用,但它并不是专门为Python设计的,其测量结果包括启动Python解释器的时间。如果你启动了大量新进程,而不是只有一个运行时间较长的进程,那么启动Python解释器的时间可能占比很高。如果要剖析的是运行时间很短的脚本,那么启动时间将占据整体运行时间的很大一部分,在这种情况下,time得到的结果将更有用。

要获得更详细的输出,可添加标志--verbose:

$ /usr/bin/time --verbose python julia1_nopil.py
Length of x: 1000
Total elements: 1000000
calculate_z_serial_purepython took 8.477287530899048 seconds
 Command being timed: "python julia1_nopil.py"
 User time (seconds): 8.97
 System time (seconds): 0.05
 Percent of CPU this job got: 99٪
 Elapsed (wall clock) time (h:mm:ss or m:ss): 0:09.03
 Average shared text size (kbytes): 0
 Average unshared data size (kbytes): 0
 Average stack size (kbytes): 0
 Average total size (kbytes): 0
 Maximum resident set size (kbytes): 98620
 Average resident set size (kbytes): 0
 Major (requiring I/O) page faults: 0
 Minor (reclaiming a frame) page faults: 26645
 Voluntary context switches: 1
 Involuntary context switches: 27
 Swaps: 0
 File system inputs: 0
 File system outputs: 0
 Socket messages sent: 0
 Socket messages received: 0
 Signals delivered: 0
 Page size (bytes): 4096
 Exit status: 0

在上述输出中,最有用的指标可能是Major(requiring I/O)page faults,它表明由于在RAM中没有找到所需的数据,操作系统必须从磁盘加载数据页。这对速度影响极大。

我们的示例涉及的代码和数据很少,不会出现缺页(page fault)问题。如果测试目标是内存密集型进程,或者是多个使用大量RAM的程序,Major(requiring I/O)page faults就可能提供线索,让你知道哪个程序因为如下情况而降低了速度:它的某些部分已经从RAM交换到磁盘中,导致操作系统需要访问磁盘。