我需要sleep
在 shell 脚本中使用,所以我在终端中尝试了它,但是它产生的延迟不一致并且非常不准确。例如sleep 3
产生接近 20 秒的延迟。当指定相同时间时,这些延迟也可能会波动。一般来说,延迟似乎随着值的增加而呈指数增长。
在 Ubuntu 和 Debian VM 上尝试过,但结果同样不佳。我认为 VM 组件没有发挥作用(timeout 10
在 Windows VM 上运行就可以了)。
通过对每个命令进行计时,系统时钟认为它运行正常,但实际上并非如此。请参阅下面的几个示例。
括号中的时间是实际经过的时间(近似值):
$ time sleep 1 (7 secs)
real 0m1.040s
user 0m0.003s
sys 0m0.016s
$ time sleep 1 (5 secs)
real 0m1.028s
user 0m0.009s
sys 0m0.013s
$ time sleep 1 (5 secs)
real 0m1.027s
user 0m0.013s
sys 0m0.007s
$ time sleep 1 (5 secs)
real 0m1.029s
user 0m0.007s
sys 0m0.016s
$ time sleep 3 (17 secs)
real 0m3.036s
user 0m0.000s
sys 0m0.021s
$ time sleep 5 (29.5 secs)
real 0m5.026s
user 0m0.007s
sys 0m0.013s
默认值显然以秒为单位,但添加s
时间并没有任何区别。
主机上没有运行任何可能占用磁盘或 CPU 的其他内容。
重新启动虚拟机似乎可以改善前几次尝试的情况,但之后准确性会变得越来越差。
知道问题可能是什么吗?
编辑:
运行
declare -p PS1
回报declare -- PS1="\${debian_chroot:+(\$debian_chroot)}\\u@\\h:\\w\\\$ "
运行
command -V sleep
回报sleep is hashed (/usr/bin/sleep)
运行
declare -p PATH
回报declare -x PATH="/home/debwp/mycmds:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
Paul_Pedant 帖子的结果:
~$ date '+%T.%N'; time sleep 5; date '+%T.%N' 22:47:49.679497552 ^[[A ^[[A ^[[A ^[[A real 0m5.033s user 0m0.005s sys 0m0.014s 22:47:54.788302324 ~$ date '+%T.%N'; time sleep 5; date '+%T.%N' 22:47:54.830674809 real 0m5.043s user 0m0.008s sys 0m0.012s 22:47:59.934542825 ~$ date '+%T.%N'; time sleep 5; date '+%T.%N' 22:47:59.994006022 real 0m5.057s user 0m0.004s sys 0m0.018s 22:48:05.159303996 ~$ date '+%T.%N'; time sleep 5; date '+%T.%N' 22:48:05.241043114 real 0m5.099s user 0m0.004s sys 0m0.021s 22:48:10.383158635 ~$ date '+%T.%N'; time sleep 5; date '+%T.%N' 22:48:10.435520982 real 0m5.028s user 0m0.004s sys 0m0.012s 22:48:15.497877219 ~$
date
以每秒一次的速度在终端输入导致$ date Mon 31 Aug 20:42:25 CEST 2020 $ date Mon 31 Aug 20:42:25 CEST 2020 $ date Mon 31 Aug 20:42:25 CEST 2020 $ date Mon 31 Aug 20:42:26 CEST 2020
答案1
该行为肯定与您的虚拟机管理程序有关。
time(7)
说:
实时被定义为从某个固定点测量的时间,可以是从过去的标准点(参见下面的纪元和日历时间的描述),也可以是从进程生命周期中的某个点(例如,开始)(经过的时间)。
进程时间定义为进程使用的 CPU 时间量。有时将其分为用户和系统组件。用户CPU时间是在用户模式下执行代码所花费的时间。系统CPU时间是内核代表进程在系统模式下执行(例如,执行系统调用)所花费的时间。 time(1) 命令可用于确定程序执行期间消耗的 CPU 时间量。
基于此,我们可以得出这样的结论:
$ time sleep 1
real 0m1.002s
user 0m0.002s
sys 0m0.000s
real
是真实时间,意味着该过程中花费的实际时间(有时称为挂钟时间)。 user
是在用户模式下执行代码所花费的 CPU 时间(CPU 周期 * 频率),并且sys
是内核代表进程在系统模式下执行所花费的 CPU 时间(CPU 周期 * 频率)。
解释一下你的问题:
为什么没有
real
报告时间time(1)
匹配我的手表吗?
当您在裸机上运行操作系统时,您通常会有一个以恒定频率运行的电池供电的晶体振荡器。该硬件时钟将跟踪自纪元以来的时间。每秒振荡的次数可以调整以校正漂移(参见hwclock(8)
)。
time(7)
还说:
设置超时(例如 select(2)、sigtimedwait(2))和测量 CPU 时间(例如 getrusage(2))的各种系统调用的精度受软件时钟分辨率的限制,软件时钟由内核维护,以 jiffy 为单位测量时间。jiffy 的大小由内核常量 HZ 的值决定。
硬件时钟用于初始化系统时钟(否则只能知道自启动以来的时间)。我怀疑您的虚拟机管理程序(virtualbox)使用一些 hwclock 来初始化时间。之后,软件时钟接管。
rtc(4)
说:
[硬件时钟]不要与系统时钟混淆,系统时钟是由内核维护的软件时钟,用于实现 gettimeofday(2) 和 time(2),以及在文件上设置时间戳等。
我们在这里刚刚了解到的是time(2)
(这是实用程序使用的库调用time(1)
)实际上从系统时钟获取信息,而不是硬件时钟。
软件时钟由内核维护,它测量时间jiffies
。这是由内核常数确定的时间单位。据我了解,一定数量的CPU周期会增加一个jiffie。因此,如果操作系统认为 CPU 运行在 2.0 GHz,但 CPU 实际上运行在 1.0GHz,那么与挂钟相比,一个 jiffie 实际上需要 2ms,而不是预期的 1ms。
当使用物理硬件运行时,我们告诉CPU我们希望它运行多快(为了省电而减慢速度,为了提高性能而加快速度),然后我们假设硬件按照它所承诺的那样运行,因为物理硬件确实做到了这一点。诀窍在于,当“硬件”是虚拟的时,管理程序决定如何控制虚拟 CPU,而不是物理定律。
在用户空间(如虚拟机)中运行的虚拟机管理程序将受主机内核的支配,为其提供所需的周期。如果主机系统运行 1000 个虚拟机,您可以想象每个来宾 VM 只会获得其预期的 CPU 周期的一部分,从而导致猜测系统时钟以较慢的速率增加。即使虚拟机管理程序获得了所需的所有资源,它也可以选择在其认为合适的情况下限制资源,从而使来宾操作系统的运行速度比预期慢,而无需了解原因。
答案2
在 Virtualbox Manager 中,将半虚拟化值(系统设置 --> 加速选项卡)从 更改为Default
更正Minimal
了问题。