병렬 쉘 루프


11

많은 파일을 처리하고 싶습니다. 여러 코어가 있으므로 병렬로 처리하고 싶습니다.

for i in *.myfiles; do do_something $i `derived_params $i` other_params; done

나는 Makefile 솔루션을 알고 있지만 명령에는 쉘 globbing 목록에서 인수가 필요합니다. 내가 찾은 것은 :

> function pwait() {
>     while [ $(jobs -p | wc -l) -ge $1 ]; do
>         sleep 1
>     done
> }
>

이를 사용하기 위해서는 작업과 pwait 호출을 모두 한 후 수행해야합니다. 매개 변수는 병렬 프로세스 수를 제공합니다.

> for i in *; do
>     do_something $i &
>     pwait 10
> done

그러나 이것은 잘 작동하지 않습니다. 예를 들어 많은 파일을 변환하는 for 루프로 시도했지만 오류가 발생하여 작업이 취소되었습니다.

zsh 메일 링리스트에 대한 토론이 너무 오래되어서 아직 완료되지 않았다는 것을 믿을 수 없습니다. 그래서 당신은 더 잘 알고 있습니까?


이 질문과 유사합니다 : superuser.com/questions/153630/… 해당 기술이 귀하에게 적합한 지 확인하십시오.
JRobert

오류 메시지를 게시하면 도움이됩니다.
추후 공지가있을 때까지 일시 중지되었습니다.

@ JRobert 예 나는 이것을 알고 있었지만 makefile 접근 방식이 내가 말한 것처럼 작동하지 않으므로 실제로 도움이되지 않습니다! @Dennis : 좋아, 먼저 지정된 수보다 많은 프로세스를 보여주는 것 외에도 top을 실행 해 보았습니다. 둘째, 프롬프트로 제대로 돌아 가지 않습니다. 셋째, 취소되지 않은 작업은 그대로 두었다고 말 echo "DONE"했는데, 활성 작업이 완료되기 전에 실행 된 루프 뒤에 표시기를 배치했습니다 . => 이로 인해 작업이 완료되지 않았다고 생각했습니다.
math

답변:


15

makefile 문제에 대한 좋은 해결책입니다. 이 병렬 실행을 쉘에서 프로그래밍 할 수는 있지만 알다시피 어렵습니다. make의 병렬 구현은 작업 시작 및 종료 감지뿐만 아니라로드 밸런싱도 처리하므로 까다로울 수 있습니다.

globbing의 요구 사항은 장애물이 아닙니다.이를 지원하는 구현이 있습니다. GNU make (와 같은 와일드 카드 확장 $(wildcard *.c)및 쉘 액세스 (예 : $(shell mycommand)자세한 내용은 GNU make 설명서 기능 참조)) makeLinux 의 기본값 이며 대부분의 다른 시스템에서 사용 가능합니다. 다음은 필요에 따라 조정할 수있는 Makefile 스켈레톤입니다.

출처 = $ (와일드 카드 * .src)

모두 : $ (sources : .src = .tgt)

% .tgt : $ .src
    do_something $ <$$ (파생 _ 매개 변수 $ <)> $ @

make -j44 개의 작업을 병렬로 실행하거나 make -j -l3로드를 약 3으로 유지하는 것과 같은 것을 실행 하십시오 .


8

나는 당신의 파생 주장이 무엇인지 잘 모르겠습니다. 그러나 GNU Parallel http : // www.gnu.org/software/parallel/을 사용하면 CPU 코어 당 하나의 작업을 수행 할 수 있습니다.

find . | parallel -j+0 'a={}; name=${a##*/}; upper=$(echo "$name" | tr "[:lower:]" "[:upper:]");
   echo "$name - $upper"'

파생하고자하는 것이 단순히 .extension을 변경하는 것이라면 {.}가 유용 할 수 있습니다

parallel -j+0 lame {} -o {.}.mp3 ::: *.wav

http://www.youtube.com/watch?v=OpaiGYxkSuQ 에서 GNU Parallel에 대한 소개 비디오를 보십시오.


7

wait명령을 사용하지 않습니까?

for i in *
do
    do_something $i &
done
wait

루프는 작업을 실행 한 다음 기다렸다가 다음 작업을 수행합니다. 위의 방법으로 문제가 해결되지 않으면 pwait이후에 이동하면 더 잘 작동 할 수 있습니다 done.


백만 개의 파일이 없으면 백만 개의 프로세스가 실행 중입니까, 아니면 잘못 되었습니까?
math

1
@ brubelsabs : 글쎄, 그것은 백만 프로세스를 하려고 합니다. 당신은 당신의 질문에 얼마나 많은 파일을 처리해야하는지 말하지 않았습니다. 중첩 for루프 를 사용 하여 다음을 제한 해야한다고 생각합니다 for file in *; do for i in {1..10}; do do_something "$i" & done; wait; done. 당신의 루프는 한 번에 하나씩 &그루터기를 만듭니다. 다른 옵션에 대해서는 JRobert가 링크 한 질문을 참조하십시오 . 스택 오버플로에서 귀하와 비슷한 다른 질문을 검색하십시오.
추후 공지가있을 때까지 일시 중지되었습니다.

OP가 백만 개의 파일을 예상하면에 문제가있는 것입니다 for i in *. 그는 파이프 또는 무언가로 루프에 인수를 전달해야 할 것입니다. 그런 다음 내부 루프 대신 증분 카운터를 실행하고 "micro-"wait"-s"모든 "$ ((i % 32))"

@ DennisWilliamson : wait내부 카운터 루프와 결합 하면 나에게 효과적이었습니다. 감사!
Joel Purra

3

왜 아무도 xargs를 언급하지 않았습니까?

정확히 세 개의 주장이 있다고 가정하면,

for i in *.myfiles; do echo -n $i `derived_params $i` other_params; done | xargs -n 3 -P $PROCS do_something

그렇지 않으면 구분 기호를 사용하십시오 (null이 유용합니다).

for i in *.myfiles; do echo -n $i `derived_params $i` other_params; echo -ne "\0"; done | xargs -0 -n 1 -P $PROCS do_something

편집 : 위의 경우 각 매개 변수는 null 문자로 구분되어야하며 xargs -n으로 매개 변수 수를 지정해야합니다.


우리 프로젝트에서 누군가 같은 아이디어를 가지고 있으며 MSys가있는 Windows에서도 훌륭하게 작동합니다.
math

0

나는 몇 가지 대답을 시도했다. 스크립트가 필요한 것보다 조금 더 복잡해집니다. 이상적으로 사용 parallel또는 xargsfor 루프가 복잡 내부의 작업이 병렬 공급 크고 긴 줄 파일을 만들 문제가 될 수 있다면 그러나 바람직 할 것이다. 대신 다음과 같이 소스를 사용할 수 있습니다

# Create a test file 
$ cat test.txt
task_test 1
task_test 2

# Create a shell source file 
$ cat task.sh
task_test()
{
    echo $1
}

# use the source under bash -c 
$ cat test.txt | xargs -n1 -I{} bash -c 'source task.sh; {}'
1
2

따라서 문제 해결 방법은 다음과 같습니다.

for i in *.myfiles; echo " do_something $i `derived_params $i` other_params
" >> commands.txt ; done

무언가를 정의하다 do_something.sh

do_something(){
process $1
echo $2 
whatever $3 

}

xarg또는로 실행gnu parallel

   cat commands.txt | xargs -n1 -I{} -P8 bash -c 'source do_something.sh; {}'

for 반복의 기능적 독립성이 내포되어 있다고 가정합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.