Criei um simulador Python que funciona com base em argumentos fornecidos pelo usuário. Para usar o programa, executo várias simulações aleatórias (controladas com um valor inicial). Eu uso o GNU paralelo para executar o simulador com argumentos de maneira semelhante à mostrada abaixo:
parallel 'run-sim --seed {1} --power {2}' ::: <seed args> ::: <power args>
Agora, há um terceiro argumento --num
que quero usar, mas quero vincular esse argumento ao valor inicial. Assim, para cada valor inicial, apenas um valor numérico é usado. No entanto, o mesmo argumento num não deve ser usado com todos os valores de potência.
Resumindo, esta tabela deve fazer você entender melhor:
| Power | Seed | num |
|:-----------|------------:|:------------:|
| 10 | 0 | 100 |
| 10 | 1 | 150 |
| 10 | 2 | 200 |
| 10 | 3 | 250 |
|:-----------|------------:|:------------:|
| 20 | 0 | 300 |
| 20 | 1 | 350 |
| 20 | 2 | 400 |
| 20 | 3 | 450 |
....
(O formato da tabela pode não ser adequado para dispositivos móveis)
Se eu escrevesse a implementação acima usando um loop for, faria algo como:
for p in power:
for s, n in (seed, num[p])
simulate(p, s, n)
Onde potência é uma matriz 1D, semente é uma matriz 1D e num é uma matriz 2D onde uma linha representa os valores num correspondentes para uma potência p.
Minha solução:
Use várias instruções paralelas para cada valor de potência e use o--link
parâmetrode paralelo para vincular os argumentos seed e num.
parallel --link 'run-sim --seed {1} --num {2} --power 10' ::: 0 1 2 3 ::: 100 150 200 250
parallel --link 'run-sim --seed {1} --num {2} --power 20' ::: 0 1 2 3 ::: 300 350 400 450
...
O problema com esta solução seria que eu teria que limitar o número de empregos para cada instrução com base no número de valores de potência. Meu computador pode lidar com 50 processos extras antes de sofrer uma parada cardíaca; portanto, para 3 valores de potência, eu teria que limitar os trabalhos de cada instrução a 12.
O que estou procurando
Um único liner para que eu não precise executar várias instruções paralelas e fixar o número de trabalhos em 50.
Responder1
Não está claro como você determina num
. Você pode usar um array baseado em potência e semente:
$ declare -A num=([10,0]=100 [10,1]=150 [10,2]=200 [10,3]=250 [20,0]=300 [20,1]=350 [20,2]=400 [20,3]=450 [30,0]=133 [30,1]=166 [30,2]=200 [30,3]=233)
$ env_parallel -j 50 echo power {1} seed {2} num '${num[{1},{2}]}' ::: 10 20 30 ::: 0 1 2 3
Ou uma matriz baseada no número de sequência:
$ num=(dummy 100 150 200 250 300 350 400 450 133 166 200 233)
$ env_parallel -j 50 echo power {1} seed {2} num '${num[{#}]}' ::: 10 20 30 ::: 0 1 2 3
Ou talvez:
parallel -j 50 echo power {1} seed '{=1 $_=(seq()-1)%4=}' num {2} ::: 10 10 10 10 20 20 20 20 30 30 30 30 :::+ 100 150 200 250 300 350 400 450 133 166 200 233
Responder2
Parapapelda resposta que você quer, correto?
$ parallel --link -k echo {1} {2} ::: {0..3} ::: {100..450..50}
0 100
1 150
2 200
3 250
0 300
1 350
2 400
3 450
Se sim, uma maneira de fazer o que acho que você quer seria
$ parallel -k echo {1} {2} ::: {10..20..10} ::: "$(parallel --link -k echo {1} {2} ::: {0..3} ::: {100..450..50})"
10 0 100
10 1 150
10 2 200
10 3 250
10 0 300
10 1 350
10 2 400
10 3 450
20 0 100
20 1 150
20 2 200
20 3 250
20 0 300
20 1 350
20 2 400
20 3 450
Outra maneira seria (com uma classificação para mostrá-lo na ordem desejada; não seria necessário na execução real):
$ parallel --link -k echo {1} {2} ::: {0..3} ::: {100..450..50} | parallel -a- echo {2} {1} ::: {10..20..10} | sort -k 1,1 -k3,3 -k2,2
10 0 100
10 1 150
10 2 200
10 3 250
10 0 300
10 1 350
10 2 400
10 3 450
20 0 100
20 1 150
20 2 200
20 3 250
20 0 300
20 1 350
20 2 400
20 3 450
Ainda outra maneira seria fazer com que o paralelo invoque paralelo:
$ parallel parallel --link --arg-sep ,,, echo {1} ,,, {0..3} ,,, {100..450..50} ::: {10..20..10}
10 0 100
10 1 150
10 2 200
10 3 250
10 0 300
10 1 350
10 2 400
10 3 450
20 0 100
20 1 150
20 2 200
20 3 250
20 0 300
20 1 350
20 2 400
20 3 450
Isso funciona porque o paralelo “interno” usa vírgulas em vez de dois pontos para separadores de argumentos, de modo que o paralelo “externo” não “vê” o argumento vinculado.
Enquanto eu estava trabalhando em uma maneira de tornar isso mais compreensível (há um suposto '{}' ali), percebi que o último exemplo não funcionaria exatamente para você, porque o segundo e o terceiro argumentos são uma string. Então adicionei o esclarecimento e (mais um!) paralelo, para demonstrar como você executaria seu simulador Python.
$ parallel parallel --link --arg-sep ,,, -I [] echo {1} [] ,,, {0..3} ,,, {100..450..50} ::: {10..20..10} | parallel -C' ' echo foo {1} bar {2} blat {3}
foo 10 bar 0 blat 100
foo 10 bar 1 blat 150
foo 10 bar 2 blat 200
foo 10 bar 3 blat 250
foo 10 bar 1 blat 350
foo 10 bar 0 blat 300
foo 10 bar 2 blat 400
foo 10 bar 3 blat 450
foo 20 bar 0 blat 100
foo 20 bar 1 blat 150
foo 20 bar 2 blat 200
foo 20 bar 3 blat 250
foo 20 bar 0 blat 300
foo 20 bar 1 blat 350
foo 20 bar 2 blat 400
foo 20 bar 3 blat 450
Para qualquer lista enumerada de valores
$ parallel parallel --link --arg-sep ,,, -I [] echo {1} [] ,,, {0..3} ,,, v0.0 v0.1 v0.2 v0.3 v1.0 v1.1 v1.2 v1.3 ::: {10..20..10} | parallel -C' ' echo power {1} seed {2} num {3}
power 20 seed 0 num v0.0
power 20 seed 1 num v0.1
power 20 seed 2 num v0.2
power 20 seed 3 num v0.3
power 20 seed 0 num v1.0
power 20 seed 1 num v1.1
power 20 seed 2 num v1.2
power 20 seed 3 num v1.3
power 10 seed 0 num v0.0
power 10 seed 1 num v0.1
power 10 seed 2 num v0.2
power 10 seed 3 num v0.3
power 10 seed 0 num v1.0
power 10 seed 1 num v1.1
power 10 seed 2 num v1.2
power 10 seed 3 num v1.3
Esta está se tornando uma resposta muito longa. Acho que talvez você queira algo mais parecido com isto, onde 1 a 12 (número de potências vezes número de sementes) são os valores únicos para cada combinação de potência e semente, e poderia ser uma lista enumerada de valores em vez de {1..12 }? Observe que estou vinculando power e seed em vez de num e seed.
$ parallel --link echo {1} {2} ::: "$(parallel echo {1} {2} ::: {10..30..10} ::: {0..3})" ::: {1..12} | parallel -C' ' echo run-sim --power {1} --seed {2} --num {3}
run-sim --power 10 --seed 0 --num 1
run-sim --power 10 --seed 1 --num 2
run-sim --power 10 --seed 2 --num 3
run-sim --power 10 --seed 3 --num 4
run-sim --power 20 --seed 0 --num 5
run-sim --power 20 --seed 1 --num 6
run-sim --power 20 --seed 2 --num 7
run-sim --power 20 --seed 3 --num 8
run-sim --power 30 --seed 0 --num 9
run-sim --power 30 --seed 1 --num 10
run-sim --power 30 --seed 2 --num 11
run-sim --power 30 --seed 3 --num 12