매초 뭔가를 확인하고 인쇄하기 위해 이 루프를 실행하고 있습니다. 그러나 계산에 수백 밀리초가 걸릴 수 있으므로 인쇄 시간이 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
zsh
Sleep이 부동 소수점 초를 지원하지 않는 경우 대신 '를 사용할 수 있습니다 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초 미만 동안 실행되는 한 표류해서는 안 됩니다.