需要循环睡眠一秒钟的时间


13

在我的机器上,我需要执行一个循环,该循环迭代1个简单命令,该命令必须以秒为单位表示延迟。

假设我需要:

  • 保存具有越来越高的enumaration的文件(file-0,file-1,file-2等),例如 time > file-$x
  • 我需要每1/70秒执行一次(例如),因为我想用几分之一秒来表示我的时间。

我怎样才能真正精确地用bash脚本表达一切?

小数可以生成不确定的数量,我需要精确,所以我至少需要4-5个小数。

Answers:


12

要将bash中的分数从小数转换为小数,请执行以下操作

myvar=$(echo "scale=4; 5/10" | bc)

然后,要对该值进行循环,

for i in $(seq 1 1000); do sleep $myvar; done

我在Debian(GNU)上的睡眠实现似乎接受十进制睡眠值。

不幸..

有了这种精度(小数点后4-5位),您将需要像perl脚本或编译程序这样的东西;在循环内调用任何程序的开销都会增加很多抖动。调用睡眠本身将花费几毫秒的时间。

考虑以下情况,即每秒睡眠的十分之一/ 10,000,已完成1000次:

time for i in $(seq 1 1000); do sleep 0.0001; done

real    0m2.099s
user    0m3.080s
sys     0m1.464s

预期的结果将是1/10秒。睡眠远没有您想要的公差。

/programming/896904/how-do-i-sleep-for-a-millisecond-in-perl

使用perl的Time :: HiRes,1000 * 1000微秒:

my $i=0;
for($i=0;$i<=1000;$i++) {
        usleep(1000);
}

real    0m1.133s
user    0m0.024s
sys     0m0.012s

使我们接近一秒钟。


如果不可能达到4-5个小数,我会选择最佳结果,但是我的意思是我需要用分数表示,而不是小数或秒。
user1717079

在任何脚本语言(包括bash)中将小数转换为十进制都是非常琐碎的。例如echo“ scale = 4; 5/10” | BC
Rob Bos 2012年

现在我已经有了如何转换表达式的问题,现在的问题是一个简单的bash真的很慢,不能简单地跟上这个频率...
user1717079 2012

是的,如果您想得到比1/10秒精确得多的精度,则可能需要perl或python,以避免程序在循环中调用开销。
罗伯·博斯

7

也许您可以简单地运行

sleep 0.7

man 1 sleep

在我的archlinux发行版上:

描述暂停NUMBER秒。SUFFIX可能是“ s”代表秒(默认值),“ m”代表分钟,“ h”代表小时或“ d”代表天。与大多数要求NUMBER为整数的实现不同,这里NUMBER可以是任意浮点数。给定两个或多个参数,暂停它们的值总和指定的时间。


sleep允许分数?您能提供一个带有假循环的完整示例吗?
user1717079

0.7这不是表达我的问题的分数...我的问题是关于粒度;考虑大约1/3,并尝试精确地睡眠。
user1717079

6

生成一个进程并在其中加载新的可执行文件可能需要花费几毫秒的时间,因此这种精确度实际上没有任何意义。还要注意,在许多系统上,CPU时间最多以10毫秒为片分配给进程。

话虽如此,有些sleep实现只需要秒的分数,并且zsh和ksh93都可以使用来使它们的$SECONDS特殊变量分数typeset -F SECONDS

示例(zsh):

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((1./70)); date +%s.%N; done | { head -n3;echo ..;tail -n3; }; echo $SECONDS
1350076317.374870501
1350076317.391034397
1350076317.407278461
..
1350076318.464585550
1350076318.480887660
1350076318.497133050
1.1393780000

糟糕,它漂移了。您可以根据以下方法调整睡眠时间$SECONDS

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do sleep $((i/70. - SECONDS)); date +%s.%N; done | { head -n3;echo ...;tail -n3; }; echo $SECONDS
1350076420.262775654
1350076420.277012997
1350076420.291302750
../..
1350076421.219682227
1350076421.234134663
1350076421.248255685
1.0020580000

这两个额外的毫秒可能是由于运行last sleepdate命令造成的。

另请注意,zsh具有一个zselect内置的超时机制,以百分之一秒表示。并且ksh93具有sleep内置功能(并接受浮点数),并且printf可以打印日期/时间。

$ typeset -F SECONDS=0; for ((i=1; i<=70; i++)); do ((i<4 || i>67)) && printf '%(%S.%N)T\n' now; sleep $((i/70.-SECONDS)); done; echo $SECONDS
20.823349000
20.837510000
20.851663000
21.780099000
21.794254000
21.808405000
0.9992358685

如果您需要更精确的信息,则可能需要使用实时操作系统或具有实时功能并且肯定使用外壳程序的操作系统。


sleep 1/70不允许在我的机器上...
user1717079

甚至不接近我想要实现的目标,我如何可以更快地执行任务?
user1717079

抱歉,用小数表示的意思不是表示为n / m,其中n和m是整数,而是表示为带小数部分的小数。我想你也可以称他们为十进制浮点数字虽然我不知道正确的英文术语
斯特凡Chazelas

我认为我要避免使用外壳...
user1717079 2012

答题者是正确的。Shell和进程通常不太适合毫秒分辨率。为了获得可靠的性能,您需要编译一个调用usleep(3)之类的程序,并且可能还需要使用不同的配置重新编译内核。或至少将不同的参数提供给内核的运行时调度程序。这是不平凡的。具有标准内核的标准Debian安装具有有限的实时功能。不过,您可能仍想检查nice(1)命令;它可能会有所帮助。
thb 2013年

3

如果您的外壳sleep不接受分数,请使用perl。

sleep_fraction() {
  /usr/bin/perl -e "select(undef, undef, undef, $1)"
}

sleep_fraction 0.01428

如果您需要找出分数,请使用 echo "scale=5; 1/70" | bc


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.