간단한 예제를 통해 쉘 스크립트에서의 병렬 처리를 이해하고 출력에 결정적으로(무작위 순서가 아닌) 순차적으로 값을 추가하려고 합니다. 코드 조각은 다음과 같습니다.
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
/////을 얻을 수도 있고, /////을 얻을 수도 있고, 더 나쁠 수도 있습니다. 비동기 프로세스를 동일한 파일에 기록하는 것은 좋지 않습니다.1b
2a
2b
3a
3b
2a
2b
1a
1b
3a
3b
2a
1a
2b
3a
3b
1b
아마도 다음과 같은 작업을 수행해야 할 것입니다.
{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]}"
parset
GNU Parallel의 일부입니다.