문제

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 개의 작업 :

Simple scheduling

GNU 병렬은 대신 CPU를 활성화하여 시간을 절약 할 때 새로운 프로세스를 스폰합니다.

GNU Parallel scheduling

자세한 내용 :

나는 최근에 이것을해야했고 다음 해결책으로 끝났다.

while true; do
  wait -n || {
    code="$?"
    ([[ $code = "127" ]] && exit 0 || exit "$code")
    break
  }
done;

작동 방식은 다음과 같습니다.

wait -n (잠재적으로 많은) 배경 작업 중 하나가 종료 되 자마자 종료됩니다. 항상 TRUE로 평가하고 루프는 다음과 같습니다.

  1. 종료 코드 127: 마지막 배경 작업이 성공적으로 종료되었습니다. 이 경우 출구 코드를 무시하고 코드 0으로 하위 쉘을 종료합니다.
  2. 배경 작업이 실패했습니다. 우리는 해당 출구 코드로 하위 쉘을 종료합니다.

와 함께 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
}

아이디어는 "직업"을 사용하여 백그라운드에서 활동하는 어린이 수를 확인 하고이 숫자가 떨어질 때까지 기다리는 것입니다 (어린이 출구). 어린이가 존재하면 다음 작업을 시작할 수 있습니다.

보시다시피, 동일한 실험/명령을 여러 번 실행하지 않도록 약간의 추가 논리도 있습니다. 그러나이 논리는 건너 뛰거나 더욱 향상 될 수 있습니다 (예 : 파일 생성 타임 스탬프, 입력 매개 변수 등).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top