4 가지 작업이 동시에 진행됩니다. 어떻게해야합니까?


23

디렉토리에 PNG 이미지가 많이 있습니다. 이 이미지를 압축하기 위해 실행하는 pngout이라는 응용 프로그램이 있습니다. 이 응용 프로그램은 내가 한 스크립트에 의해 호출됩니다. 문제는이 스크립트가 다음과 같이 한 번에 하나씩 수행한다는 것입니다.

FILES=(./*.png)
for f in  "${FILES[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 $f R${f/\.\//}
done

한 번에 하나의 파일 만 처리하는 데 많은 시간이 걸립니다. 이 응용 프로그램을 실행 한 후 CPU가 10 %에 불과하다는 것을 알았습니다. 그래서 나는이 파일들을 4 개의 배치로 나누고, 각 배치를 디렉토리에 넣고 4 개의 터미널 창에서 4 개의 프로세스로 4를 발사 할 수 있다는 것을 발견했습니다. 따라서 동시에 스크립트의 4 개의 인스턴스가 있습니다. 직업은 1/4의 시간이 걸립니다.

두 번째 문제는 이미지와 배치를 나누고 스크립트를 4 개의 디렉토리에 복사하고 4 개의 터미널 창을 열고 bla bla ...

아무것도 나누지 않고 하나의 스크립트로 어떻게합니까?

두 가지 의미 : 먼저 bash 스크립트에서 프로세스를 백그라운드로 실행하려면 어떻게해야합니까? 두 번째 : 네 번째 작업을 보낸 후 백그라운드로 작업 보내기를 중지하고 작업이 끝날 때까지 스크립트를 기다리려면 어떻게해야합니까? 하나의 작업이 끝날 때마다 새로운 작업을 백그라운드로 보내서 항상 4 개의 작업을 병렬로 유지한다는 의미입니까? 내가 그렇게하지 않으면 루프가 수십억 개의 작업을 백그라운드로 시작하고 CPU가 막힙니다.


답변:


33

xargs와의 병렬 실행을 지원 하는 사본이있는 경우 -P간단하게 수행 할 수 있습니다

printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}

다른 아이디어를 위해 Wooledge Bash 위키에는 프로세스 관리 기사에서 원하는 것을 정확하게 설명 하는 섹션 이 있습니다.


2
이 경우를 위해 설계된 "gnu parallel"및 "xjobs"도 있습니다. 그것은 주로 당신이 선호하는 맛의 문제입니다.
wnoise

제안 된 명령을 설명해 주시겠습니까? 감사!
Eugene S

1
@EugeneS 어떤 부분에 대해 좀 더 구체적으로 설명해 주시겠습니까? printf는 모든 png 파일을 수집하고 파이프를 통해 xargs로 전달합니다. xargs는 표준 입력에서 인수를 수집 pngout하여 OP가 실행하려는 명령에 대한 인수로 결합합니다 . 키 옵션은 -P 4xargs가 최대 4 개의 동시 명령을 사용하도록 지시합니다.
jw013

2
정확하지 않아 죄송합니다. 나는 왜 printf규칙적이기보다는 여기에서 함수 를 사용했는지에 특히 관심이 있었 ls .. | grep .. *.png습니까? 또한 xargs사용 한 매개 변수 ( -0-I{}) 에 관심이있었습니다 . 감사!
Eugene S

3
@EugeneS 정확성과 견고성을 극대화합니다. 파일 이름은 줄이 아니므로 파일 이름을 ls이식 가능하고 안전하게 구문 분석하는 데 사용할 수 없습니다 . 파일 이름을 구분하는 데 사용할 수있는 유일한 안전한 문자는 \0및입니다 /.를 포함하여 다른 모든 문자 \n는 파일 이름 자체의 일부일 수 있습니다. printf용도 \0를 단락 파일 이름 및 -0정보 용 xargs이의. 이 인수 로 대체하라는 -I{}지시 입니다. xargs{}
jw013

8

이미 제안 된 솔루션 외에도 압축 파일에서 압축 파일을 작성하고 make -j 44 개의 작업을 병렬로 실행 하는 방법을 설명하는 makefile을 작성할 수 있습니다 . 문제는 압축 및 압축되지 않은 파일의 이름을 다르게 지정하거나 다른 디렉토리에 저장해야한다는 것입니다. 그렇지 않으면 합리적인 작성 규칙을 작성하는 것이 불가능합니다.



5

두 가지 질문에 대답하려면 :

  • 예, 줄의 끝에 &를 추가하면 쉘이 백그라운드 프로세스를 시작하도록 지시합니다.
  • wait명령을 사용하면 쉘이 백그라운드의 모든 프로세스가 완료 될 때까지 기다렸다가 계속 진행할 수 있습니다.

j백그라운드 프로세스 수를 추적하는 데 사용 되도록 수정 된 스크립트는 다음과 같습니다 . 경우 NB_CONCURRENT_PROCESSES에 도달 할 때 스크립트가 재설정됩니다 j0과 그것의 실행을 다시 시작하기 전에 모두 완료 될 때까지 백그라운드 프로세스를 기다립니다.

files=(./*.png)
nb_concurrent_processes=4
j=0
for f in "${files[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 "$f" R"${f/\.\//}" &
        ((++j == nb_concurrent_processes)) && { j=0; wait; }
done

1
이것은 4 개의 동시 프로세스 중 마지막 프로세스를 기다린 다음 다른 4 개의 프로세스를 시작합니다. 아마도 하나는 4 개의 PID 배열을 구축 한 다음 이러한 특정 PID를 기다려야합니까?
Nils

코드에 대한 수정 사항을 설명하기 위해 : (1) 스타일 문제로, 모든 대문자 변수 이름은 잠재적으로 내부 쉘 변수와 충돌하므로 피하십시오. (2) 따옴표 $f등을 추가했습니다 . (3) [POSIX 호환 스크립트에 사용하지만 순수한 bash [[에는 항상 선호됩니다. 이 경우 ((산술에 더 적합합니다.
jw013
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.