Como iniciar dois threads no script de shell bash?

3

Estou tentando copiar arquivos de machineB e machineC para machineA enquanto estou executando meu script de shell abaixo em machineA .

Se os arquivos não estiverem em machineB , eles devem estar em machineC , então tentarei copiar os arquivos de machineB primeiro, se ele não estiver em machineB , então tentarei copiando os mesmos arquivos de machineC .

Eu estou copiando os arquivos em paralelo usando a biblioteca GNU Parallel e está funcionando bem. Atualmente estou copiando dois arquivos em paralelo.

Atualmente, estou copiando os arquivos PRIMARY_PARTITION na pasta PRIMARY usando o GNU paralelo e, uma vez feito isso, copio os arquivos SECONDARY_PARTITION na pasta SECONDARY usando o mesmo GNU paralelo para que ele seja sequencial a partir de agora wrt PRIMARY e SECONDARY pasta

Abaixo está o meu script de shell e tudo funciona bem -

#!/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[@]}"

Descrição do problema: -

Existe alguma maneira de lançar dois threads, um para copiar arquivos na pasta PRIMARY usando a mesma configuração que eu acima, o que significa que ele copiará dois arquivos em paralelo. E segundo thread para copiar os arquivos na pasta SECONDARY usando a mesma configuração que eu acima, ele também deve copiar dois arquivos paralelos simultaneamente?

Isso significa que eles devem copiar os arquivos em paralelo na pasta PRIMARY e SECONDARY simultaneamente, não depois que a pasta PRIMARY estiver pronta e, em seguida, copiar os arquivos na pasta SECONDARY .

Atualmente, quando o arquivo da pasta PRIMARY é concluído, apenas tento copiar os arquivos na pasta SECONDARY .

Em suma, eu só preciso lançar dois tópicos um segmento irá executar este -

# 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[@]}"

E o segundo thread executará isso -

# 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[@]}"

E assim que todos os arquivos forem copiados com sucesso, ele deverá ecoar a mensagem, que todos os arquivos são copiados. No java, eu sei como iniciar dois threads e cada thread está executando determinada tarefa, mas não sabe como no script de shell bash isso vai funcionar?

Minha principal tarefa é copiar dois arquivos em paralelo usando o GNU paralelo na pasta PRIMARY e na pasta SECONDARY ao mesmo tempo?

Isso é possível no script de shell bash?

    
por arsenal 19.05.2014 / 05:54

3 respostas

3

O óbvio é:

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

Mas desta forma o secundário não espera que o primário termine e não verifica se o primário foi bem sucedido. Vamos supor que $ PRIMARY_PARTITION [1] corresponda a $ SECONDARY_PARTITION [1] (portanto, se você não puder ler o arquivo de $ PRIMARY_PARTITION [1] você irá ler a partir de $ SECONDARY_PARTITION [1] - Isso também significa que $ PRIMARY_PARTITION e $ SECONDARY_PARTITION têm o mesmo número de elementos). Então você pode condicionar a execução de $ SECONDARY_PARTITION [1] em $ PRIMARY_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

Isto irá acertar a dependência, mas copiará apenas 2 de cada vez no total. Com -j4 você corre o risco de executar 4 primárias ao mesmo tempo, então precisamos nos proteger contra isso também:

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 limitará o número de primárias a 2 e o número de secundárias a 2.

    
por 19.05.2014 / 08:22
4

O Bash não suporta segmentação, mas suporta o multiprocessamento em segundo plano. Ou seja, o processo é clonado em um novo espaço de processo, com seu próprio ambiente, diretório de trabalho, etc, e toda a comunicação precisa acontecer através de canais IPC normais. Mas caso contrário, parece muito com segmentação.

Você faz isso "fazendo o background" de um bloco de código. Assim:

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

saída

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

Você pode obter o mesmo efeito agrupando um bloco de código em uma função e executando essa função como um trabalho em segundo plano.

Como alternativa, você pode envolver seu bloco de código entre parênteses em vez de chaves. As declarações entre parênteses explicitamente (e sempre) são executadas em um processo separado; Normalmente, as instruções entre chaves são agrupadas, mas executadas sem bifurcação. Executar o código em segundo plano usando o sufixo & força esse código a ser executado em um processo separado.

    
por 19.05.2014 / 08:12
0

Seria uma boa idéia usar o rsync em vez do scp para isso. Copiando todos os arquivos em um comando, em vez de executar o scp para cada arquivo, você economizará muito tempo e esforço e ajudará a garantir que os dados sejam copiados corretamente. Ele também irá ignorar a cópia de arquivos existentes do machineC. Algo parecido com isto:

#!/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
    
por 19.05.2014 / 15:19