GNU paralelo - dois parâmetros da matriz como parâmetro

4

Eu tenho um script que usa o gnu paralelo. Eu quero passar dois parâmetros para cada "iteração"

na execução serial eu tenho algo como:

for (( i=0; i<=10; i++ ))
do
  a = tmp1[$i]
  b = tmp2[$i]
done

E eu quero fazer este paralelo como

func pf()
{
   a=$1
   b=$2
}
export -f pf
parallel --jobs 5 --linebuffer pf ::: <what to write here?>
    
por Martin Perry 30.09.2017 / 14:59

2 respostas

4

Omitindo seus outros sinalizadores parallel apenas para manter o foco ...

parallel --link pf ::: A B ::: C D

Isso executará sua função primeiro com a=A , b=C seguido por a=B , b=D ou

a=A b=C
a=B b=D

Sem --link você recebe uma combinação completa assim:

a=A b=C
a=A b=D
a=B b=C
a=B b=D

Atualização: como Ole Tange metioned em um comentário existe outra maneira de fazer isso, o operador :::+ . Existe uma diferença importante entre as duas alternativas SE o número de argumentos não é o mesmo em cada posição do parâmetro . Um exemplo ilustrará:

parallel --link pf ::: A B ::: C D E output:

a=A b=C
a=B b=D
a=A b=E

parallel pf ::: A B :::+ C D E output:

a=A b=C
a=B b=D

--link irá "quebrar" para que todos os argumentos sejam consumidos, enquanto :::+ irá ignorar o argumento extra. Pessoalmente, não gosto quando as coisas são ignoradas silenciosamente, e é por isso que minha preferência é --link . YMMV.

    
por 30.09.2017 / 15:24
1

Para simplificar, vou assumir o bash e que os arrays são indexados a partir de 1 em vez de 0. Parece intuitivo querer fazer algo assim:

parallel ... pf '$tmp1[{#}]' '$tmp2[{#}]' ::: $(seq 10)

onde os dois argumentos para sua função pf são parte do comando, e usamos a notação paralela {#} para representar o número do trabalho (que é definido como 1 até 10 para 10 trabalhos. Simplesmente usamos seq para obter 10 argumentos após o ::: para garantir que façamos 10 trabalhos (os valores seq não são usados e, por acaso, são iguais aos números do trabalho).

Infelizmente, isso não funcionará porque o bash não exporta variáveis de matriz. Mas ele pode exportar funções, e a página parallel man mostra a solução alternativa usando uma função import_array simples para exportar / importar uma função de sua escolha, my_importer que irá definir as variáveis de array de sua escolha:

declare -a tmp1 tmp2
for (( i=1; i<=10; i++ ))
do tmp1[$i]=x$i
   tmp2[$i]=y$i
done

import_array(){
    local func=$1; shift;
    export $func='() {
      '"$(for arr in $@; do
            declare -p $arr|sed '1s/declare -./&g/'
          done)"'
    }'
}
import_array my_importer tmp1 tmp2

Precisamos apenas informar parallel para passar a função my_importer para o ambiente do comando pf , com a opção --env my_importer , e depois executar essa função antes de executar pf :

pf(){ a=$1; b=$2; echo "job a=$a b=$b"; }
export -f pf 

parallel -v --jobs 5 --linebuffer \
 --env my_importer 'my_importer;'  pf '${tmp1[{#}]}' '${tmp2[{#}]}' ::: $(seq 10)

A saída resultante com -v é semelhante a

my_importer; pf ${tmp1[2]} ${tmp2[2]}
my_importer; pf ${tmp1[1]} ${tmp2[1]}
my_importer; pf ${tmp1[5]} ${tmp2[5]}
my_importer; pf ${tmp1[3]} ${tmp2[3]}
job a=x1 b=y1
my_importer; pf ${tmp1[6]} ${tmp2[6]}
job a=x2 b=y2
my_importer; pf ${tmp1[7]} ${tmp2[7]}
job a=x4 b=y4
...
    
por 30.09.2017 / 18:48