如何使每个循环花费完全相同的时间?

如何使每个循环花费完全相同的时间?

ENV :GNU bash,版本 4.2.46(2)-release (x86_64-redhat-linux-gnu)(旧的)


  • 我希望每个循环花费相同的时间。
  • 循环永远不会停止
  • api_call函数正常运行大约需要1s~5s。
  • 由于网络问题,API 调用很少会挂起直到 60 秒超时。

我的脚本A

TIMEFORMAT=%R
while true; do
  time=$(date +'%F %T')
  api_result=$( { time api_call; } 2>api_runtime.txt )
  api_runtime=$(cat api_runtime.txt)
  echo "${time} ${api_result}"
  sleep (( 10 - ${api_runtime} ))
done

我认为 Scrit A 会完成这项工作,直到有一天网络变慢并且循环不同步。


我的脚本B

TIMEFORMAT=%R
while true; do
  time=$(date +'%F %T')
  api_result=$( api_call & )
  sleep 10
  echo "${time} ${api_result:-No response}"
done

脚本 B 目前似乎也可以工作,但我不确定在下一个循环api_call需要超过 10 秒时是否安全。


我该如何实现这一目标?

答案1

在命令替换内部使用&不会与主脚本同时在后台运行该命令,只会运行该命令替换中发生的其他事情。

$ time str=$( (sleep 2; echo hello) & )

real    0m2.006s
user    0m0.000s
sys     0m0.003s
$ echo "$str"
hello

上面的作业在完成之前会挂起两秒钟,下面的作业也是如此。

$ time str=$( echo hello & sleep 2; echo bye )

real    0m2.011s
user    0m0.000s
sys     0m0.006s
$ echo "$str"
hello
bye

这意味着您sleep 10没有必要(或者更确切地说,它总是会增加循环体​​的运行时间 10 秒),因为它前面的行上的赋值将阻塞,直到执行为止,这将在api_call终止时发生。

如果您希望每次循环迭代花费 60 秒(您提到的超时长度):

while true; do
    result=$( sleep 60 & api_call )
done

这确保了分配将花费 60 秒,即使api_call返回时间比该时间短。

或者,

while true; do
    result=$( sleep 10 & timeout 10s api_call )
done

api_call...这需要 10 秒,如果比这慢,则显式发送 TERM 信号。

如果这是一个长时间运行的脚本,您会期望它会逐渐漂移。一个潜在的解决方案是使用 cron 作业定期重新安排它(终止正在运行的脚本并重新执行它)。

相关内容