時間要花多少時間?

時間要花多少時間?

shell 关键字time可用于计时一个进程需要多长时间,但time它本身实际上会给该进程增加多少开销?

换句话说,使用以下命令计时,命令运行速度会慢多少time

time grep "a string"

...比没有计时的时候更是如此:

grep "a string"

答案1

初步说明

有时很容易混淆time实用程序。您明确询问了“shell 关键字time”。


代码

以下代码将运行测量true(这是 Bash 中的内置 shell)n次,然后测量true相同次数。减去相应的结果并除以n

export n=10000000
time bash -c 'for ((i=1;i<=n;i++)); do time true; done' 2>/dev/null
time bash -c 'for ((i=1;i<=n;i++)); do      true; done' 2>/dev/null

例子

n=10000000分别得到:

real    1m32.693s
user    1m13.679s
sys     0m18.998s

real    0m39.344s
user    0m39.343s
sys     0m0.000s

各自的区别:

real    53.349s
user    34.336s
sys     18.998s

每人time

real    5.3349μs
user    3.4336μs
sys     1.8998μs

分析

这些取决于操作系统的一般和临时速度,因此您的结果会有所不同。我的测试平台是一台配备 i7 CPU、Kubuntu 18.04.3 LTS、Bash 4.4.20 的笔记本电脑。我还有一台速度慢得多的电脑作为家用路由器/服务器。结果如下,,36μs。现在你知道预期的幅度了。21μs15μs

我也测试了不同的值n. 总时间表现出良好的线性。换句话说,“每人time”的结果不依赖于n. 就我的代码而言,这是预料之中的。


结论

time在我的 Bash 中,测量精度为 1 毫秒。即使在相对较慢的计算机上,开销也小 20 倍以上。我想说这是可以忽略不计的。


奖金

另一个怎么样time

在我的笔记本电脑上,我将time循环中的 替换为/usr/bin/time(并在两行中​​都替换为,因为true无法使用内置函数)。这些是使用 获得的每个结果(略有四舍五入):/bin/true/usr/bin/time truetrue/usr/bin/timen=100000

real    600μs
user    530μs
sys      80μs

外部可执行文件比内置可执行文件慢 100 倍左右。实际上,一次调用/usr/bin/time可能需要更长的时间,因为操作系统可能需要从硬盘读取可执行文件。然后文件被缓存,因此在我的人工测试中,循环的其余部分会受益,并且如果n足够大。

相比之下,timeBash 提供的速度即使是第一次运行也应该同样快,因为bash已经加载了(但我还没有测试过)。

回到/usr/bin/time。我预计在较慢的机器上开销很容易超过 1 毫秒。

答案2

time您可以通过将其包装到另一个来测试需要花费多少time

time time true

注意:我添加的true是“不执行任何操作”的简单命令。

true - 不执行任何操作,成功 -man true

在我的电脑上,它显示:

real:0m0.000s user:0m0.000s sys:0m0.000s

即使发生了 20 次:

$ time time time time time time time time time time time time time time time time time time time time true true
real:0m0.000s user:0m0.000s sys:0m0.000s

这里有 1000 个:

$ eval $(for i in $(seq 1 1000); do printf "time "; done) true
real:0m0.000s user:0m0.000s sys:0m0.000s

man time给出了一些有关如何计算时间的线索:

time 显示的大部分信息来自 wait3(2) 系统调用。这些数字仅与 wait3(2) 返回的数字一样好。在没有 wait3(2) 调用返回状态信息的系统上,将改用 times(2) 系统调用。但是,它提供的信息比 wait3(2) 少得多,因此在这些系统上,time 将大多数资源报告为零。

如需了解更多技术细节,请查看:man 2 wait3man wait4


要在 Linux 上调试time,你可以使用strace,例如

$ strace -f time true

要计算系统调用的时间(-c)并总结时间差异(-s),请运行:

$ strace -fwc time true
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 30.91    0.007723          69       112           write
 27.19    0.006794        6794         1           wait4
 20.44    0.005107         340        15        13 execve
  7.43    0.001855        1855         1           clone
  2.94    0.000734         122         6         6 access
...

time以下是调试10次的方法:

$ strace -fwc $(echo $(for i in $(seq 1 10); do printf "time "; done)) true | head
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 87.35    1.057704      105770        10           wait4
  7.33    0.088807          79      1120           write
  2.25    0.027275         222       123       112 execve
  1.37    0.016571        1657        10           clone
  0.32    0.003913          71        55           mmap
  0.32    0.003844         116        33        33 access
  ...

1000次之后:

$ strace -fwc $(echo $(for i in $(seq 1 100); do printf "time "; done)) true | head
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 98.66  112.115311     1121153       100           wait4
  0.77    0.874091          78     11200           write
  0.24    0.271382         226      1203      1102 execve
  0.16    0.179477        1795       100           clone
  0.03    0.037229         123       303       303 access
  0.03    0.036702          73       505           mmap
...

显然在调试器下运行时,运行实际命令时时间会更慢,但它可以大致了解正在使用哪种系统调用以及与其他系统调用相比它们可以使用多少时间。

答案3

原则上,time 所做的只是等待(字面意思是,它会调用 ,从而完全停止自身进程wait3()的执行)子进程完成,然后向内核询问子进程的资源使用情况统计信息。因此, 几乎不会对子进程的运行时间产生任何影响。timetime

这些统计数据似乎总是被收集。似乎没有“启动监控”模式或会减慢子进程速度的某些东西。我在这里使用“似乎”,因为我无法查看代码,也找不到明确证实这一点的来源。

来源/这个兔子洞的入口:http://man7.org/linux/man-pages/man2/wait4.2.html

相关内容