디렉토리에 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가 막힐 것입니다.
답변1
xargs
을(를) 사용하여 병렬 실행을 지원하는 복사본이 있는 경우 -P
간단히 다음을 수행할 수 있습니다.
printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}
다른 아이디어에 대해서는 Wooledge Bash 위키에 있습니다.부분원하는 것을 정확하게 설명하는 프로세스 관리 기사에서.
답변2
이미 제안된 솔루션 외에도 압축되지 않은 파일에서 압축된 파일을 만드는 방법을 설명하는 makefile을 생성하고 make -j 4
4개의 작업을 병렬로 실행하는 데 사용할 수 있습니다. 문제는 압축된 파일과 압축되지 않은 파일의 이름을 다르게 지정하거나 다른 디렉터리에 저장해야 한다는 것입니다. 그렇지 않으면 합리적인 make 규칙을 작성하는 것이 불가능합니다.
답변3
GNU 병렬이 있는 경우http://www.gnu.org/software/parallel/설치하면 다음과 같이 할 수 있습니다:
parallel ./pngout -s0 {} R{} ::: *.png
다음과 같이 간단하게 GNU Parallel을 설치할 수 있습니다.
wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
자세히 알아보려면 GNU Parallel 소개 비디오를 시청하세요. https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
답변4
두 가지 질문에 답하려면:
- 예, 줄 끝에 &를 추가하면 쉘이 백그라운드 프로세스를 시작하도록 지시합니다.
- 이
wait
명령을 사용하면 더 이상 진행하기 전에 백그라운드의 모든 프로세스가 완료될 때까지 기다리도록 셸에 요청할 수 있습니다.
j
다음은 백그라운드 프로세스 수를 추적하는 데 사용되도록 수정된 스크립트입니다 . 에 도달 하면 NB_CONCURRENT_PROCESSES
스크립트는 j
0으로 재설정되고 실행을 재개하기 전에 모든 백그라운드 프로세스가 완료될 때까지 기다립니다.
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