스크립트의 배쉬 배경 작업이 완료 될 때까지 기다립니다.
-
16-09-2019 - |
문제
CPU 사용량을 최대화하려면 (EC2의 데비안 레니에서 물건을 실행합니다) 작업을 동시에 시작하는 간단한 스크립트가 있습니다.
#!/bin/bash
for i in apache-200901*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200902*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200903*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200904*.log; do echo "Processing $i ..."; do_something_important; done &
...
이 작업 솔루션에 매우 만족하지만 모든 루프가 완료되면 실행 된 추가 코드를 작성하는 방법을 알 수 없었습니다.
이것을 제어 할 수있는 방법이 있습니까?
해결책
거기에 bash
그것에 대한 명령.
wait [n ...]
Wait for each specified process and return its termination sta‐
tus. Each n may be a process ID or a job specification; if a
job spec is given, all processes in that job’s pipeline are
waited for. If n is not given, all currently active child pro‐
cesses are waited for, and the return status is zero. If n
specifies a non-existent process or job, the return status is
127. Otherwise, the return status is the exit status of the
last process or job waited for.
다른 팁
GNU 병렬을 사용하면 스크립트가 더 짧고 더 효율적일 수 있습니다.
parallel 'echo "Processing "{}" ..."; do_something_important {}' ::: apache-*.log
이렇게하면 CPU 코어 당 하나의 작업이 실행되며 모든 파일이 처리 될 때까지 계속합니다.
솔루션은 기본적으로 작업을 실행하기 전에 그룹으로 분할합니다. 여기 4 개 그룹의 32 개의 작업 :
GNU 병렬은 대신 CPU를 활성화하여 시간을 절약 할 때 새로운 프로세스를 스폰합니다.
자세한 내용 :
- 빠른 소개를 보려면 소개 비디오를보십시오.https://www.youtube.com/playlist?list=pl284c9ff248bc6d1
- 튜토리얼 (Man Parallel_Tutorial)을 걸어 가십시오. 당신은 명령 줄이 당신을 사랑할 것입니다.
나는 최근에 이것을해야했고 다음 해결책으로 끝났다.
while true; do
wait -n || {
code="$?"
([[ $code = "127" ]] && exit 0 || exit "$code")
break
}
done;
작동 방식은 다음과 같습니다.
wait -n
(잠재적으로 많은) 배경 작업 중 하나가 종료 되 자마자 종료됩니다. 항상 TRUE로 평가하고 루프는 다음과 같습니다.
- 종료 코드
127
: 마지막 배경 작업이 성공적으로 종료되었습니다. 이 경우 출구 코드를 무시하고 코드 0으로 하위 쉘을 종료합니다. - 배경 작업이 실패했습니다. 우리는 해당 출구 코드로 하위 쉘을 종료합니다.
와 함께 set -e
, 이는 스크립트가 조기에 종료되고 실패한 배경 작업의 종료 코드를 통과 할 것입니다.
이것은 나의 조잡한 해결책입니다.
function run_task {
cmd=$1
output=$2
concurency=$3
if [ -f ${output}.done ]; then
# experiment already run
echo "Command already run: $cmd. Found output $output"
return
fi
count=`jobs -p | wc -l`
echo "New active task #$count: $cmd > $output"
$cmd > $output && touch $output.done &
stop=$(($count >= $concurency))
while [ $stop -eq 1 ]; do
echo "Waiting for $count worker threads..."
sleep 1
count=`jobs -p | wc -l`
stop=$(($count > $concurency))
done
}
아이디어는 "직업"을 사용하여 백그라운드에서 활동하는 어린이 수를 확인 하고이 숫자가 떨어질 때까지 기다리는 것입니다 (어린이 출구). 어린이가 존재하면 다음 작업을 시작할 수 있습니다.
보시다시피, 동일한 실험/명령을 여러 번 실행하지 않도록 약간의 추가 논리도 있습니다. 그러나이 논리는 건너 뛰거나 더욱 향상 될 수 있습니다 (예 : 파일 생성 타임 스탬프, 입력 매개 변수 등).