for 루프와 GNU 병렬?

for 루프와 GNU 병렬?

이에 가까운 답변을 찾았지만 내 경우에는 어떻게 사용하는지 이해할 수 없습니다(저는 Bash를 처음 접했습니다)... 그래서 대량의 이미지 시퀀스(100,000개 이상의 파일)가 포함된 폴더를 처리하려고 합니다. Imagemagick을 사용하고 GNU Parallel을 사용하면 작업 속도가 향상되기를 바랍니다.

다음은 제가 사용하는 코드입니다(메모리 부족을 방지하기 위해 한 번에 100프레임을 처리함).

calcmethod1=mean;
allframes=(*.png)
cd out1

for (( i=0; i < "${#allframes[@]}" ; i+=100 )); do 
    convert "${allframes[@]:i:100}" -evaluate-sequence "$calcmethod1" \
        -channel RGB -normalize ../out2/"${allframes[i]}"
done

이것을 어떻게 "병렬화"합니까? 내가 찾은 대부분의 솔루션은 루프가 아닌 파이프를 사용하지만 이렇게 하면 매개변수 목록이 너무 길어져서 스크립트가 중단되는 문제가 발생했습니다.

내가 원하는 것은 parallel로드를 분할하는 것입니다. 예를 들어 처음 100개 프레임을 코어 1에 제공하고, 프레임 100-199를 코어 2에 제공하는 식입니다.

답변1

주문하다

귀하의 예제 프로그램은 구성하는 배열의 순서에 관심이 없는 것 같지만 *.png귀하 allframes의 의견을 통해 순서가 중요하다고 믿게 되었습니다.

내가 원하는 것은 로드를 병렬로 분할하는 것입니다. 예를 들어 처음 100개 프레임을 코어 1에 제공하고 프레임 100-199를 코어 2에 제공하는 등의 작업을 수행하는 것입니다.

불다

그래서 먼저 아래와 같이 스크립트를 수정하여 allframes파일이 번호순으로 저장되도록 배열의 구조를 변경했습니다.

allframes=($(printf "%s\n" *.png | sort -V | tr '\n' ' '))

이는 다음을 사용하여 더욱 단순화할 수 있습니다 sort -zV.

allframes=($(printf "%s\0" *.png | sort -zV | tr '\0' ' '))

이는 convert ...빌드 명령에 영향을 미치므로 이제 다음과 같습니다.

$ convert "0.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png \
          10.png 11.png 12.png 13.png 14.png 15.png 16.png 17.png 18.png \
          19.png 20.png 21.png 22.png 23.png 24.png 25.png 26.png 27.png \
          28.png 29.png 30.png 31.png 32.png 33.png 34.png 35.png 36.png \
          37.png 38.png 39.png 40.png 41.png 42.png 43.png 44.png 45.png \
          46.png 47.png 48.png 49.png 50.png 51.png 52.png 53.png 54.png \
          55.png 56.png 57.png 58.png 59.png 60.png 61.png 62.png 63.png \
          64.png 65.png 66.png 67.png 68.png 69.png 70.png 71.png 72.png \
          73.png 74.png 75.png 76.png 77.png 78.png 79.png 80.png 81.png \
          82.png 83.png 84.png 85.png 86.png 87.png 88.png 89.png 90.png \
          91.png 92.png 93.png 94.png 95.png 96.png 97.png 98.png 99.png" \
          -evaluate-sequence "mean" -channel RGB -normalize ../out2/0.png

유사점

paralleleschwartz의 예를 바탕으로 다음과 같은 예를 구성했습니다 .

$ printf '%s\n' *.png | sort -V | parallel -n100 --dryrun convert {} \
   -evaluate-sequence 'mean' -channel RGB -normalize ../out2/{1}

다시 한 번 사용하기가 더 간단합니다 sort -zV.

$ printf '%s\0' *.png | sort -zV | parallel -0 -n100 --dryrun "convert {} \
   -evaluate-sequence 'mean' -channel RGB -normalize ../out2/{1}

노트:parallel시작 작업 으로 위에 에코 "..."가 있습니다 . 이렇게 하면 무슨 일이 일어나고 있는지 시각화하는 데 도움이 됩니다.

$ convert 0.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png 10.png \
         11.png 12.png 13.png 14.png 15.png 16.png 17.png 18.png 19.png \
         20.png 21.png 22.png 23.png 24.png 25.png 26.png 27.png 28.png \
         29.png 30.png 31.png 32.png 33.png 34.png 35.png 36.png 37.png \
         38.png 39.png 40.png 41.png 42.png 43.png 44.png 45.png 46.png \
         47.png 48.png 49.png 50.png 51.png 52.png 53.png 54.png 55.png \ 
         56.png 57.png 58.png 59.png 60.png 61.png 62.png 63.png 64.png \ 
         65.png 66.png 67.png 68.png 69.png 70.png 71.png 72.png 73.png \ 
         74.png 75.png 76.png 77.png 78.png 79.png 80.png 81.png 82.png \
         83.png 84.png 85.png 86.png 87.png 88.png 89.png 90.png 91.png \
         92.png 93.png 94.png 95.png 96.png 97.png 98.png 99.png \
         -evaluate-sequence mean -channel RGB -normalize ../out2/0.png

이 출력이 만족스러우면 스위치를 로 옮기고 --dryrun다시 parallel실행하십시오.

$ printf '%s\0' *.png | sort -zV | parallel -0 -n100 convert {} \ 
    -evaluate-sequence 'mean' -channel RGB -normalize

인용하다

답변2

printf '%s\0' *.png올바른 해결책은 명령줄 인수 길이에 대한 ARG_MAX 제한에 영향을 받지 않는 셸 내장 명령을 사용하여 파일 이름을 인쇄한 다음 파이프를 통해 parallel --null해당 파일 이름을 읽고 필요에 따라 작업을 일괄 처리하는 것입니다.

parallel우리는 다음 기능 중 일부를 사용합니다:

  • --null이상한 파일 이름으로 인한 이상한 문제를 방지하려면 파일 이름을 null 문자로 현명하게 분할해야 합니다.
  • -n 100xargs와 마찬가지로 각 호출은 100개의 파일을 처리합니다.
  • {}다음 100개의 파일 이름이 포함되어 있습니다.
  • ../out2/{1}첫 번째 항목만 포함

따라서 이는 다음과 같습니다.

calcmethod1=mean
printf '%s\0' *.png | parallel --null -n 100 convert {} -evaluate-sequence $calcmethod1 -channel RGB -normalize {} ../out2/{1}

왜 파이프가 작동하지 않는다고 생각하시나요? 파이프라인은 잘 작동하지만 외부 분기 명령만 작동합니다.아니요파이프에서 읽는 중, 문제매개변수 길이. 파이프는 실제로 parallel.

답변3

convert각 프로세스는 자체 서브셸에서 실행될 수 있습니다.

#!/bin/bash

for (( i=1; i<=1000; i++ )) do
(
command --options ) &
disown
done

exit 0

작동 방식을 보려면 다음 스크립트를 시도해 보세요.

#!/bin/bash

echo "Hi!"

for (( i=1; i<=1000; i++ )) do
(
sleep 30
echo "Bye, "$i"!" ) &
disown
done

exit 0

스크립트 이름을 지정한 par.sh후 프로세스를 확인하십시오.

ps aux | grep par.sh

각 하위 셸에는 별도의 PID가 있으므로 기본 Linux CPU 로드 밸런서는 프로세스를 CPU 코어에 균등하게 분산해야 한다고 가정할 수 있습니다. 어쨌든 비슷한 것은 cpuset항상 사용할 수 있습니다.

관련 정보