2013-05-16 9 views
7

Ho un ciclo while in Bash gestito in questo modo:parallelizzazione un ciclo while con gli array letti da un file in bash

while IFS=$'\t' read -r -a line; 
do 
    myprogram ${line[0]} ${line[1]} ${line[0]}_vs_${line[1]}.result; 
done < fileinput 

Si legge da un file con questa struttura, per riferimento:

foo bar 
baz foobar 

e così via (delimitato da tabulazioni).

Vorrei parallelizzare questo ciclo (poiché le voci sono molte e l'elaborazione può essere lenta) usando GNU parallelo, tuttavia gli esempi non sono chiari su come assegnerei ogni linea all'array, come faccio qui.

Quale sarebbe una possibile soluzione (alternative al lavoro parallelo di GNU pure)?

risposta

8

Da https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Use-a-table-as-input:

"""
Contenuto del table_file.tsv:

foo<TAB>bar 
baz <TAB> quux 

Per eseguire:

cmd -o bar -i foo 
cmd -o quux -i baz 

si può lanciare:

parallel -a table_file.tsv --colsep '\t' cmd -o {2} -i {1} 

"""

Quindi nel tuo caso sarà:

cat fileinput | parallel --colsep '\t' myprogram {1} {2} {1}_vs_{2}.result 
3

parallel non è strettamente necessario qui; avvia tutti i processi in background, quindi attendi che vengano completati. L'array è anche inutile, come si può dare read più di una variabile per popolare:

while IFS=$'\t' read -r f1 f2; 
do 
    myprogram "$f1" "$f2" "${f1}_vs_${f2}.result" & 
done < fileinput 
wait 

Questo si avvia un unico lavoro per ogni elemento nell'elenco, mentre parallel possono limitare il numero di posti di lavoro in esecuzione al una volta. È possibile eseguire lo stesso in bash, ma è difficile.

+0

C'è un modo per farlo con un limite massimo di processo? Altrimenti, eseguendolo su grandi input si apre - edit, non vedi la risposta di Hubbitus – nmr

3

Mi piacerebbe @chepner hack. E non sembra così difficile realizzare un comportamento simile con il numero di esecuzioni parallele limitativo:

while IFS=$'\t' read -r f1 f2; 
do 
    myprogram "$f1" "$f2" "${f1}_vs_${f2}.result" & 

    # At most as number of CPU cores 
    [ $(jobs | wc -l) -ge $(nproc) ] && wait 
done < fileinput 

wait 

Esso limita l'esecuzione al massimo numero di nuclei di CPU presenti nel sistema. Si può facilmente variare sostituendo $(nproc) con la quantità desiderata.

Nel frattempo dovresti capire cosa non è la distribuzione onesta. Quindi, non inizia una nuova discussione subito dopo aver finito. Invece aspetta solo di finire tutto, dopo l'ammontare massimo iniziale. Quindi il throughput di sintesi può essere leggermente inferiore rispetto a quello parallelo. Soprattutto se il tempo di esecuzione del tuo programma può variare a grande distanza. Se il tempo impiegato per ogni invocazione è quasi lo stesso, anche il tempo di sintesi dovrebbe essere approssimativamente equivalente.