Bash
Parallelo
Ricerca…
introduzione
I lavori in GNU Linux possono essere parallelizzati usando GNU parallel. Un lavoro può essere un singolo comando o un piccolo script che deve essere eseguito per ciascuna delle righe nell'input. L'input tipico è un elenco di file, un elenco di host, un elenco di utenti, un elenco di URL o un elenco di tabelle. Un lavoro può anche essere un comando che legge da una pipe.
Sintassi
- parallel [opzioni] [comando [argomenti]] <lista_delle_grumenti>
Parametri
Opzione | Descrizione |
---|---|
-jn | Esegui n lavori in parallelo |
-k | Mantieni lo stesso ordine |
-X | Argomenti multipli con il contesto sostituito |
--colsep regexp | Dividi l'input su regexp per le sostituzioni posizionali |
{} {.} {/} {/.} {#} | Corde di ricambio |
{3} {3.} {3/} {3/.} | Stringhe di sostituzione posizionali |
-S sshlogin | Example: [email protected] |
--trc {}.bar | Abbreviazione di --transfer --return {} .bar --cleanup |
--onall | Esegui il comando dato con argomento su tutti gli sshlogins |
--nonall | Esegui il comando dato senza argomenti su tutti gli sshlogins |
--pipe | Split stdin (input standard) per più lavori. |
--recend str | Registrare il separatore finale per --pipe. |
--recstart str | Registrare il separatore iniziale per --pipe. |
Parallelizza le attività ripetitive sull'elenco di file
Molti lavori ripetitivi possono essere eseguiti in modo più efficiente se si utilizzano più risorse del computer (ad esempio CPU e RAM). Di seguito è riportato un esempio di esecuzione di più lavori in parallelo.
Supponiamo di avere un < list of files >
, per esempio l'output di ls
. Inoltre, lascia che questi file siano compressi in bz2 e il seguente ordine di attività deve essere eseguito su di essi.
- Decomprimi i file bz2 usando
bzcat
stdout - Grep (es. Filtro) linee con parole chiave specifiche usando
grep <some key word>
- Pipe l'output da concatenare in un singolo file
gzip
usandogzip
L'esecuzione di questo con un ciclo while potrebbe essere simile a questa
filenames="file_list.txt"
while read -r line
do
name="$line"
## grab lines with puppies in them
bzcat $line | grep puppies | gzip >> output.gz
done < "$filenames"
Usando GNU Parallel, possiamo eseguire 3 processi paralleli contemporaneamente semplicemente facendo
parallel -j 3 "bzcat {} | grep puppies" ::: $( cat filelist.txt ) | gzip > output.gz
Questo comando è semplice, conciso e più efficiente quando il numero di file e le dimensioni del file sono grandi. I lavori vengono avviati in parallel
, l'opzione -j 3
avvia 3 processi paralleli e l'input per i lavori paralleli viene eseguito da :::
. L'output viene infine inviato a gzip > output.gz
Parallelizzare STDIN
Ora, immaginiamo di avere 1 file di grandi dimensioni (ad es. 30 GB) che deve essere convertito, riga per riga. Diciamo che abbiamo uno script, convert.sh
, che fa questo <task>
. Siamo in grado di reindirizzare il contenuto di questo file a stdin per il parallelo da includere e lavorare con chunk come
<stdin> | parallel --pipe --block <block size> -k <task> > output.txt
dove <stdin>
può provenire da qualcosa come cat <file>
.
Come esempio riproducibile, il nostro compito sarà nl -n rz
. Prendi qualsiasi file, il mio sarà data.bz2
e data.bz2
a <stdin>
bzcat data.bz2 | nl | parallel --pipe --block 10M -k nl -n rz | gzip > ouptput.gz
L'esempio precedente prende <stdin>
da bzcat data.bz2 | nl
, dove ho incluso nl
come prova del concetto che l'output finale output.gz
verrà salvato nell'ordine in cui è stato ricevuto. Quindi, parallel
divide lo <stdin>
in blocchi di dimensione 10 MB, e per ogni blocco lo passa attraverso nl -n rz
dove aggiunge semplicemente numeri giustificati (vedi nl --help
per ulteriori dettagli). Le opzioni --pipe
dice in parallel
per dividere <stdin>
in più lavori e -- block
specifica la dimensione dei blocchi. L'opzione -k
specifica che l'ordine deve essere mantenuto.
Il tuo risultato finale dovrebbe essere simile a qualcosa
000001 1 <data>
000002 2 <data>
000003 3 <data>
000004 4 <data>
000005 5 <data>
...
000587 552409 <data>
000588 552410 <data>
000589 552411 <data>
000590 552412 <data>
000591 552413 <data>
Il mio file originale aveva 552.413 linee. La prima colonna rappresenta i lavori paralleli e la seconda colonna rappresenta la numerazione delle righe originale passata al parallel
in blocchi. Si dovrebbe notare che l'ordine nella seconda colonna (e resto del file) viene mantenuto.