Bash 쉘 스크립트에서 두 개의 스레드를 시작하는 방법은 무엇입니까?

Bash 쉘 스크립트에서 두 개의 스레드를 시작하는 방법은 무엇입니까?

machineB작업 중이어서 파일을 복사하려고 합니다 .machineCmachineAmachineA

파일이 없으면 machineB분명히 존재해야 하므로 machineC먼저 파일을 복사해 보고 machineB, 없으면 machineB에서 동일한 파일을 복사해 보겠습니다 machineC.

저는 GNU 병렬 라이브러리를 사용하여 파일을 병렬로 복사하고 있는데 잘 작동합니다. 현재 두 개의 파일을 병렬로 복사하고 있습니다.

현재 나는 GNU를 사용하여 폴더 PRIMARY_PARTITION의 파일을 PRIMARY병렬로 복사하고 있으며 일단 완료되면 동일한 GNU를 사용하여 폴더 SECONDARY_PARTITION의 파일을 SECONDARY병렬로 복사할 것입니다. 지금까지는 연속 PRIMARY적이고 SECONDARY폴더

아래는 내 쉘 스크립트입니다. 모든 것이 잘 작동합니다.

#!/bin/bash

export PRIMARY=/test01/primary
export SECONDARY=/test02/secondary
readonly FILERS_LOCATION=(machineB machineC)
export FILERS_LOCATION_1=${FILERS_LOCATION[0]}
export FILERS_LOCATION_2=${FILERS_LOCATION[1]}
PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers

export dir3=/testing/snapshot/20140103

# delete primary files first and then copy
find "$PRIMARY" -mindepth 1 -delete

do_CopyInPrimary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/.
}
export -f do_CopyInPrimary
parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}"

# delete secondary files first and then copy
find "$SECONDARY" -mindepth 1 -delete

do_CopyInSecondary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/.
}
export -f do_CopyInSecondary
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}"

문제 설명:-

두 개의 스레드를 시작할 수 있는 방법이 있습니까? 하나의 스레드는 PRIMARY위와 동일한 설정을 사용하여 폴더의 파일을 복사합니다. 즉, 두 파일을 병렬로 복사한다는 의미입니다. 두 번째 스레드는 SECONDARY위와 동일한 설정을 사용하여 폴더의 파일을 복사합니다. 두 파일도 동시에 병렬로 복사해야 합니까?

이는 폴더가 완료된 후 폴더의 파일을 복사하는 것이 PRIMARY아니라 폴더의 파일을 동시에 병렬로 복사해야 함을 의미합니다 .SECONDARYPRIMARYSECONDARY

현재는 PRIMARY폴더 파일이 완성되면 나만 SECONDARY폴더 안의 파일을 복사하려고 합니다.

즉, 두 개의 스레드를 시작하면 됩니다. 하나의 스레드가 이를 실행합니다.

# delete primary files first and then copy
find "$PRIMARY" -mindepth 1 -delete

do_CopyInPrimary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $PRIMARY/.
}
export -f do_CopyInPrimary
parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}"

두 번째 스레드는 이것을 실행합니다 -

# delete secondary files first and then copy
find "$SECONDARY" -mindepth 1 -delete

do_CopyInSecondary() {
  el=$1
  scp david@$FILERS_LOCATION_1:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/. || scp david@$FILERS_LOCATION_2:$dir3/new_weekly_2014_"$el"_200003_5.data $SECONDARY/.
}
export -f do_CopyInSecondary
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}"

모든 파일이 성공적으로 복사되면 모든 파일이 복사되었습니다라는 메시지가 표시됩니다. Java에서는 두 개의 스레드를 시작하고 각 스레드가 특정 작업을 수행하는 방법을 알고 있지만 이것이 bash 쉘 스크립트에서 어떻게 작동하는지 잘 모르십니까?

PRIMARY내 주요 작업은 SECONDARYGNU 병렬을 사용하여 폴더 안팎으로 두 개의 파일을 동시에 복사하는 것입니다.

bash 쉘 스크립트에서 이 작업을 수행할 수 있습니까?

답변1

Bash는 스레드를 지원하지 않지만 백그라운드 다중 처리를 지원합니다. 즉, 프로세스는 자체 환경, 작업 디렉터리 등을 갖춘 새로운 프로세스 공간으로 복제되며 모든 통신은 일반 IPC 채널을 통해 이루어져야 합니다. 그러나 그 외에는 스레드와 매우 유사해 보입니다.

코드 블록을 "컨텍스트화"하여 이를 수행할 수 있습니다. 이와 같이:

#!/bin/bash
{
    echo "Foo"
    sleep 1
    echo "Foo: done"
}&    
echo "Bar"
sleep 1
echo "Bar: done"

산출

Bar
Foo
**[1 second delay]**
Bar: done
Foo: done

함수에 코드 블록을 래핑하고 해당 함수를 백그라운드 작업으로 실행하면 동일한 효과를 얻을 수 있습니다.

또는 중괄호 대신 괄호로 코드 블록을 묶을 수 있습니다. 중괄호로 묶인 문은 명시적으로(항상) 별도의 프로세스에서 실행됩니다. 일반적으로 중괄호로 묶인 문은 그룹화되지만 런타임에서는 분기되지 않습니다. 접미사를 사용하여 백그라운드에서 코드를 실행하면 &코드가 별도의 프로세스에서 실행됩니다.

답변2

명백한 것들은 다음과 같습니다:

parallel -j 2 do_CopyInPrimary ::: "${PRIMARY_PARTITION[@]}" &
parallel -j 2 do_CopyInSecondary ::: "${SECONDARY_PARTITION[@]}" &
wait

그러나 이런 방식으로 보조 서버는 기본 서버가 완료될 때까지 기다리지 않으며 기본 서버가 성공했는지 확인하지도 않습니다. $PRIMARY_PARTITION[1]이 $SECONDARY_PARTITION[1]에 해당한다고 가정합니다. 따라서 $PRIMARY_PARTITION[1]에서 파일을 읽을 수 없으면 $SECONDARY_PARTITION[1]에서 파일을 읽습니다. 이는 또한 $PRIMARY_PARTITION 및 $SECONDARY_PARTITION을 의미합니다. 동일한 수의 요소가 있습니다). 그런 다음 $PRIMARY_PARTITION[1]에서 $SECONDARY_PARTITION[1]의 작동을 규제할 수 있습니다.

do_Copy() {
  PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
  SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers
  pel=${PRIMARY_PARTITION[$1]}
  sel=${SECONDARY_PARTITION[$1]}
  do_CopyInPrimary $pel || 
    do_CopyInSecondary $sel || 
    echo Could not copy neither $pel nor $sel
}
export -f do_Copy
# Number of elements in PRIMARY_PARTITION == SECONDARY_PARTITION
seq ${#PRIMARY_PARTITION[@]} | parallel -j 2 do_Copy

이렇게 하면 종속성이 정확해지지만 한 번에 총 2개만 복사됩니다. -j4동시에 4개의 예비 선거가 있을 위험이 있으므로 이에 대해서도 주의해야 합니다 .

do_Copy() {
  PRIMARY_PARTITION=(550 274 2 546 278) # this will have more file numbers
  SECONDARY_PARTITION=(1643 1103 1372 1096 1369) # this will have more file numbers
  pel=${PRIMARY_PARTITION[$1]}
  sel=${SECONDARY_PARTITION[$1]}
  sem -j2 --fg --id primary do_CopyInPrimary $pel || 
    sem -j2 --fg --id secondary do_CopyInSecondary $sel || 
    echo Could not copy neither $pel nor $sel
}
export -f do_Copy
# Number of elements in PRIMARY_PARTITION == SECONDARY_PARTITION
seq ${#PRIMARY_PARTITION[@]} | parallel -j 4 do_Copy

sem기본 수량을 2개, 보조 수량을 2개로 제한합니다.

답변3

이를 위해서는 scp 대신 rsync를 사용하는 것이 좋습니다. 각 파일에 대해 scp를 실행하는 대신 하나의 명령으로 모든 파일을 복사하면 많은 시간과 노력을 절약하고 데이터가 올바르게 복사되도록 할 수 있습니다. 또한 machineC에서 기존 파일 복사를 건너뜁니다. 이 같은:

#!/bin/bash

files="one two three"
machines="machineB machineC"

for machine in machines
do
    ssh $machine -c "cd source_directory || exit 1; rsync -avPz --ignore-existing $files machineA:/receive_directory/"
done

관련 정보