2013-05-07 6 views
8

Sto valutando se GNU Parallel può essere utilizzato per cercare i file memorizzati su un sistema in parallelo. Può esserci un solo file per ogni giorno dell'anno (doy) sul sistema (quindi un massimo di 366 file all'anno). Diciamo che ci sono 3660 file sul sistema (circa 10 anni di dati). Il sistema potrebbe essere un Linux multi-core multi-CPU o un Solaris multi-CPU.Come nutrire una vasta gamma di comandi su GNU Parallel?

Sto memorizzando i comandi di ricerca per l'esecuzione sui file in un array (un comando per file). E questo è quello che sto facendo in questo momento (utilizzando bash), ma poi non ho alcun controllo su quante ricerche per avviare in parallelo (sicuramente non vuole ricominciare tutto 3660 le ricerche in una volta):

#!/usr/bin/env bash 
declare -a cmds 
declare -i cmd_ctr=0 

while [[ <condition> ]]; do 
    if [[ -s $cur_archive_path/log.${doy_ctr} ]]; then 
     cmds[$cmd_ctr]="<cmd_to_run>" 
     let cmd_ctr++ 
    fi 
done 

declare -i arr_len=${#cmds[@]} 
for ((i=0; i<${arr_len}; i++)); 
do 
    # Get the command and run it in background 
    eval ${cmds[$i]} & 
done 
wait 

Se dovessi usare parallel (che calcolerà automaticamente il numero massimo di CPU/core e avviare solo così tante ricerche in parallelo), come posso riutilizzare l'array cmds con il parallelo e riscrivere il codice precedente? L'altra alternativa è di scrivere tutti i comandi in un file e poi fare cat cmd_file | parallel

+0

Per essere pedante, nel mio universo 10 anni non possono produrre 3660 file poiché non ci possono essere 10 anni bisestili consecutivi. Ma dal momento che hai scritto "about" presumo tu lo sappia e non guardi il mio da un universo parallelo (che mi rattrista un po ') ;-) –

+0

@Adrian Hai ragione; Ho aggiunto "about" per tenere conto degli anni bisestili :) –

risposta

6

https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Using-shell-variables dice:

parallel echo ::: "${V[@]}" 

non si vuole l'eco, in modo da:

parallel ::: "${cmds[@]}" 

Se non è necessario $ cmds per qualsiasi altra cosa, quindi usare 'sem' (che è un alias per parallelo --semaphore) https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Working-as-mutex-and-counting-semaphore

while [[ <condition> ]]; do 
    if [[ -s $cur_archive_path/log.${doy_ctr} ]]; then 
    sem -j+0 <cmd_to_run> 
    fi 
done 
sem --wait 

Non è stato descritto cosa potrebbe essere la condizione <. Se si sta semplicemente facendo un qualcosa di simile a un ciclo for si potrebbe sostituire l'intero script con:

parallel 'if [ -s {} ] ; then cmd_to_run {}; fi' ::: $cur_archive_path/log.{1..3660} 

(sulla base di https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Composed-commands).

+0

Grazie per tutti i suggerimenti. Ma ho la sensazione che la shell esploda se "$ {cmds [@]}" è espanso in linea, specialmente se l'array cmds contiene 1000 elementi/comandi al suo interno? Pensi sia più sicuro alimentare i comandi da un file? –

+0

Inoltre, quando '$ {cmds [@]}' è espanso, qual è il delimitatore tra più comandi (devo usare un ';' alla fine di ogni comando)? Com'è diverso da 'cat cmd_file | parallel' dove suppongo che un nuovo carattere di linea sia considerato un separatore di comandi? –

+0

Posso eseguire righe di comando di 130 KB, quindi se il tuo comando è <130 caratteri, dovresti essere sicuro. Ma personalmente avrei semplicemente eseguito il pipe dei comandi in parallelo (evitando così sia il limite della shell che un file temporaneo) o lasciando che i comandi paralleli venissero generati. –