정확히 1초마다 한 번씩 루프를 실행합니다.

정확히 1초마다 한 번씩 루프를 실행합니다.

매초 뭔가를 확인하고 인쇄하기 위해 이 루프를 실행하고 있습니다. 그러나 계산에 수백 밀리초가 걸릴 수 있으므로 인쇄 시간이 1초를 건너뛰는 경우도 있습니다.

매초마다 인쇄물을 얻을 수 있도록 보장하는 이와 같은 루프를 작성하는 방법이 있습니까? (물론, 루프의 계산 시간이 1초 미만인 경우 :))

while true; do
  TIME=$(date +%H:%M:%S)
  # some calculations which take a few hundred milliseconds
  FOO=...
  BAR=...
  printf '%s  %s  %s\n' $TIME $FOO $BAR
  sleep 1
done

답변1

원래 코드에 더 가까워지기 위해 내가 한 일은 다음과 같습니다.

while true; do
  sleep 1 &
  ...your stuff here...
  wait # for sleep
done

이는 의미를 약간 변경합니다. 작업에 1초 미만이 소요되면 1초가 지날 때까지 기다립니다. 그러나 어떤 이유로든 작업이 1초보다 오래 걸리면 더 많은 하위 프로세스가 계속 생성되지 않으며 절대 끝나지 않습니다.

따라서 작업이 병렬로 실행되거나 백그라운드에서 실행되지 않으므로 변수가 예상대로 작동합니다.

다른 백그라운드 작업도 시작하는 경우 해당 프로세스 wait만 구체적으로 기다리도록 지침을 변경해야 합니다 .sleep

더 정확해야 하는 경우 시스템 시계에 동기화하고 전체 초가 아닌 밀리초 동안 절전 모드로 전환할 수 있습니다.


시스템 시계와 동기화하는 방법은 무엇입니까? 정말 모르겠어, 멍청한 시도:

기본:

while sleep 1
do
    date +%N
done

출력: 003511461 010510925 016081282 021643477 028504349 03... (지속적으로 증가)

동기화됨:

 while sleep 0.$((1999999999 - 1$(date +%N)))
 do
     date +%N
 done

출력: 002648691 001098397 002514348 001293023 001679137 00... (변경되지 않은 상태로 유지됨)

답변2

루프를 스크립트/oneliner로 재구성할 수 있는 경우 가장 쉬운 방법은 다음을 사용하는 것입니다.watch그리고 그 precise옵션.

다음 명령을 사용하여 효과를 확인할 수 있습니다 watch -n 1 sleep 0.5. 초 수를 표시하지만 가끔 1초를 건너뛰는 경우도 있습니다. 이를 실행하면 watch -n 1 -p sleep 0.5매초마다 두 번씩 출력이 출력되며 건너뛰는 현상이 표시되지 않습니다.

답변3

백그라운드 작업으로 실행되는 서브셸에서 작업을 실행하면 해당 작업이 sleep.

while true; do
  (
    TIME=$(date +%T)
    # some calculations which take a few hundred milliseconds
    FOO=...
    BAR=...
    printf '%s  %s  %s\n' "$TIME" "$FOO" "$BAR"
  ) &
  sleep 1
done

1초에서 "훔친" 유일한 시간은 서브쉘을 실행하는 데 소요된 시간이므로 결국 1초를 건너뛰게 되지만 원래 코드보다 짧을 수 있기를 바랍니다.

서브쉘의 코드가 다음을 사용하게 되면1초도 안 되어 루프는 백그라운드 작업을 누적하기 시작하고 결국 리소스가 부족해집니다.

답변4

그리고 zsh:

n=0
typeset -F SECONDS=0
while true; do
  date '+%FT%T.%2N%z'
  ((++n > SECONDS)) && sleep $((n - SECONDS))
done

zshSleep이 부동 소수점 초를 지원하지 않는 경우 대신 '를 사용할 수 있습니다 zselect(나중에 zmodload zsh/zselect).

zmodload zsh/zselect
n=0
typeset -F SECONDS=0
while true; do
  date '+%FZ%T.%2N%z'
  ((++n > SECONDS)) && zselect -t $((((n - SECONDS) * 100) | 0))
done

루프의 명령이 1초 미만 동안 실행되는 한 표류해서는 안 됩니다.

관련 정보