쉘 병렬 처리: 부가 가치

쉘 병렬 처리: 부가 가치

간단한 예제를 통해 쉘 스크립트에서의 병렬 처리를 이해하고 출력에 결정적으로(무작위 순서가 아닌) 순차적으로 값을 추가하려고 합니다. 코드 조각은 다음과 같습니다.

x=""
appendnum() {
    num=$1; x=`echo $x$num`
}
for no in {0..10}
do
    appendnum $no &
done
wait $(jobs -rp)
echo $x

예상 출력은 012345678910이었지만 결과는 null이었습니다. 완료될 때까지 PID를 반복하려고 시도했지만 성공하지 못했습니다. 메인 스레드가 각 병렬 프로세스가 완료될 때까지 기다리기를 원합니다. 추가 수치는 예시일 뿐입니다.

내 문제 설명은 다음과 같습니다. 3개의 작업이 있다는 점을 고려하면 다음과 같은 응답 목록을 원합니다 [responseof(task1),responseof(task2),responseof(task3)]. 작업 수는 최대 50개까지 가능합니다. 작업 수에 관계없이 응답 시간은 동일해야 합니다. 가장 효율적이고 올바른 방법은 무엇입니까?

답변1

내가 올바르게 이해했다면 다음을 원합니다.

  • 작업을 병렬로 실행합니다. 이상적으로는 단일 작업을 실행하는 시간 내에 이러한 모든 작업이 완료되도록 해야 합니다. (매우 현실적이지는 않지만 최선을 다해 노력해보겠습니다)
  • 일부 후속 작업이 이전 작업보다 먼저 완료되더라도 출력 순서를 유지합니다.

이를 염두에 두고 다음을 시도해 볼 수 있습니다.

parallel -k -j10 'sleep {}; echo -n {}' ::: {10..1}

실행되는 첫 번째 작업이 가장 오래 걸리지만 -k옵션을 추가했기 때문에 parallel유틸리티는 순서를 유지하고 결국 출력합니다.

10987654321

-k옵션이 없으면 출력이 반전되어 명령이 완료되면 나타납니다.

12345678910

자세한 정보가 필요하면 튜토리얼을 확인하세요.https://www.gnu.org/software/parallel/parallel_tutorial.html

답변2

당신이 놓치고 있는 것:

  • 쉘 변수는 쉘 메모리, 즉 쉘 프로세스의 메모리에 저장됩니다.
  • 대부분의 명령은 하위 프로세스에서 실행되는 셸에서 실행됩니다. 유일한 예외는 "내장 명령"입니다.
  • 비동기 명령은 프로그램을 실행하지 않더라도 항상 하위 프로세스에서 실행됩니다. 프로그램을 실행하지 않는 비동기 명령은 셸만 실행하는 하위 프로세스입니다. 이것을 "서브쉘"이라고 합니다.
  • 일반적으로 프로세스는 다른 프로세스의 메모리를 변경할 수 없습니다. 특히 서브쉘은 메인 쉘 프로세스의 변수를 수정할 수 없습니다. 그래서 당신이 말할 때 appendnum $no &, appendnum기능 할 수 없다x기본 셸 프로세스에서 변수를 수정합니다 .

원하는 것과 유사한 동작을 얻을 수 있습니다.

x=TR007.out
> "$x"
appendnum() {
    echo "$1" >> "$x"
}
for no in {0..10}
do
    appendnum $no &
done
wait

파일에 0부터 10까지의 숫자를 씁니다 TR007.out.

  • 비동기 프로세스의 스케줄링(순서 지정)은 비결정적입니다. 따라서 위의 예제 스크립트에서는 0부터 10까지의 숫자를 파일에 쓰더라도 순서가 맞지 않을 수 있습니다.
  • 아시다시피 wait매개변수 없이 자체적으로 모든 하위 프로세스를 기다립니다.
  • "작업 수에 관계없이 응답 시간이 동일해야 합니다." 이는 매우 과감한 기대/요구 사항입니다. 이것이 합리적인지 여부는 상황에 따라 다릅니다. 작업이 단일 스레드 컴퓨팅 집약적 작업이고 3개 이상의 (논리적) CPU가 있는 경우에는 3개의 작업을 병렬로 실행하는 것이 하나의 작업 자체보다 시간이 조금 더 걸릴 것으로 예상하는 것이 합리적입니다. . 하지만 논리 CPU가 4개라면 완전히 괜찮습니다.무모한하나의 작업과 동일한 시간 내에 50개의 작업이 실행될 것으로 예상됩니다.
  • 하위(비동기) 프로세스가 예상된 순서로 실행된다고 언급했습니다. 동시에(즉, 병렬로) 실행되므로 실행이 겹칠 수 있습니다. 따라서 위 스크립트를 다음과 같이 변경하면
    부록(){
        에코 "$1"a>>"$x"
        에코 "$1"b>>"$x"
    }
    {1..3}의 "아니요"에 대해
    하다
        부록 $아니요 &
    완벽한
    그런 다음 파일에서 /////를 얻을 수도 있고, 1a/////을 얻을 수도 있고, /////을 얻을 수도 있고, 더 나쁠 수도 있습니다. 비동기 프로세스를 동일한 파일에 기록하는 것은 좋지 않습니다.1b2a2b3a3b2a2b1a1b3a3b2a1a2b3a3b1b

아마도 다음과 같은 작업을 수행해야 할 것입니다.

{1..3}의 "아니요"에 대해
하다
    작업 "$no" > 파일 "$no" &
완벽한
기다리다
cat 파일 1 파일 2 파일 3 > 결과 결합
기타 참고사항:

  • $(command)같은 일을 하면서. 테이블에 붙어 있어야합니다.`command`$(command)
  • 말하든 말든 의미가 없습니다. 말하다.x=`echo $x$num`x=$(echo $x$num)x="$x$num"
  • 그렇게 하지 않을 타당한 이유가 없고 자신이 무엇을 하고 있는지 확실히 알고 있지 않는 한 항상 쉘 변수를 인용해야 합니다. 그러니 하지 마세요 appendnum $no.appendnum "$no"

답변3

[응답(태스크1),응답(태스크2),응답(태스크3)]

parset다음을 위해 제작되었습니다:

parset result responseof ::: task1 task2 task3
echo "${result[1]}"

예를 들어:

parset res seq ::: 3 2 1
echo "${res[1]}"

parsetGNU Parallel의 일부입니다.

관련 정보