2009-05-06 11 views
5

Qual è il modo migliore/più semplice per creare un sistema di code di attività minimo per Linux che utilizza strumenti bash e comuni?"Coda di attività" minima con strumenti Linux di serie per sfruttare la CPU multicore

Ho un file con 9'000 righe, ogni riga ha una riga di comando bash, i comandi sono completamente indipendenti.

command 1 > Logs/1.log 
command 2 > Logs/2.log 
command 3 > Logs/3.log 
... 

La mia scatola ha più di un core e voglio eseguire attività X contemporaneamente. Ho cercato sul web un buon modo per farlo. Apparentemente, molte persone hanno questo problema, ma nessuno ha una buona soluzione finora.

Sarebbe bello se la soluzione aveva le seguenti caratteristiche:

  • grado di interpretare più di un comando (ad es command; command)
  • può interpretare flusso reindirizza sulle linee (ad esempio ls > /tmp/ls.txt) solo
  • utilizza strumenti Linux comuni

Punti bonus se funziona su altri cloni Unix senza requisiti troppo esotici.

risposta

13

È possibile convertire l'elenco dei comandi in un Makefile? Se è così, puoi semplicemente eseguire "make -j X".

+0

Perfetto, questo ha funzionato come un fascino! – Manuel

0

OK, dopo aver postato la domanda qui, ho trovato il seguente progetto che sembra promettente: ppss.

Modifica: non proprio quello che voglio, PPSS è focalizzato sull'elaborazione di "tutti i file nella directory A".

0

Beh, questo è comunque un tipo di domanda divertente.

Ecco cosa farei, supponendo bash (1) ovviamente.

  • capire quanti di questi comandi possono essere utilizzati in modo concorrente. Non sarà solo il numero di core; molti comandi saranno sospesi per I/O e quel genere di cose. Chiama quel numero N. N=15 per esempio.
  • impostare un gestore di segnale trap per il segnale SIGCHLD, che si verifica quando termina un processo figlio. trap signalHandler SIGCHLD
  • cat l'elenco dei comandi in una pipe
  • scrive un ciclo che legge stdin ed esegue i comandi uno per uno, diminuendo un contatore. Quando il contatore è 0, è wait s.
  • il tuo gestore di segnale, che gira su SIGCHLD, incrementi tale contatore.

Quindi ora esegue i primi comandi N, quindi attende. Quando il primo figlio termina, l'attesa ritorna, legge un'altra riga, esegue un nuovo comando e attende di nuovo.

Ora, questo è un caso che si occupa di molti lavori che si chiudono vicini.Ho il sospetto che si può ottenere via con una versione più semplice:

N=15 
COUNT=N 
cat mycommands.sh | 
while read cmd 
do 
    eval $cmd & 
    if $((count-- == 0)) 
    then 
     wait 
    fi 
od 

Ora, questo inizierà i primi 15 comandi e quindi eseguire il resto uno alla volta come alcuni termina di comando.

0

Offriamo le xargs comando, le sue --max-proc fa quello che si vuole. Per esempio soluzione Charlie Martin diventa con xargs:

tr '\012' '\000' <mycommands.sh |xargs --null --max-procs=$X bash -c 

dettagli:

  • X è il numero di processi max. Es: X = 15. --max-procs sta facendo la magia
  • il primo TR è qui per interrompere le linee di byte nulli per l'opzione di xargs --null in modo che cita il reindirizzamento ecc non sono espanso da torto
  • bash -c esegue il comando

ho provato con questo file mycommands.sh per esempio:

date 
date "+%Y-%m-%d" >"The Date".txt 
wc -c <'The Date'.txt >'The Count'.txt 
0

si tratta di un caso specifico, ma se si sta cercando di elaborare un insieme di file e produrre un altro set di file di output, si può iniziare #cores numero di processi e verificare se esiste un file di output prima di pro cessarlo. L'esempio seguente converte una directory di file .m4b .mp3 file:

basta eseguire questo comando tutte le volte che avete core:

ls * m4b | mentre leggere f; fai test -f $ {f% m4b} mp3 || mencoder -di rawaudio "$ f" -oac mp3lame -ovc copy -o $ {f% m4b} mp3; done &

9

GNU Parallel http://www.gnu.org/software/parallel/ è uno strumento più generale per la parallelizzazione rispetto a PPSS.

Se RUNFILE contiene:

command 1 > Logs/1.log 
command 2 > Logs/2.log 
command 3 > Logs/3.log 

si può fare:

cat runfile | parallel -j+0 

che verrà eseguito un comando per core CPU.

Se i comandi sono semplici come sopra di voi non è nemmeno necessario RUNFILE ma può fare:

seq 1 3 | parallel -j+0 'command {} > Logs/{}.log' 

Se si dispone di più computer a disposizione per fare il trattamento si consiglia di guardare al --sshlogin e Opzioni --trc per GNU Parallel.

0

Inoltre Task Queue + parallelized + dinamica

Utilizzando un FIFO, questo script forcella stessa per elaborare la coda. In questo modo, puoi aggiungere comandi alla coda al volo (quando la coda è già stata avviata).

Usage: Comando ./queue [# dei bambini] [Nome coda]

Esempio, con 1 filo:

 
./queue "sleep 5; echo ONE" 
./queue "echo TWO" 

uscita:

 
ONE 
TWO 

Esempio, con 2 fili :

 
./queue "sleep 5; echo ONE" 2 
./queue "echo TWO" 

O scita:

 
TWO 
ONE 

Esempio, con 2 code:

 
./queue "sleep 5; echo ONE queue1" 1 queue1 
./queue "sleep 3; echo ONE queue2" 1 queue2 

uscita:

 
ONE queue2 
ONE queue1 

Lo script (salvarlo come "coda" e chmod + x coda):

 

    #!/bin/bash 

    #Print usage 
    [[ $# -eq 0 ]] && echo Usage: $0 Command [# of children] [Queue name] && exit 

    #Param 1 - Command to execute 
    COMMAND="$1" 

    #Param 2 - Number of childs in parallel 
    MAXCHILD=1 
    [[ $# -gt 1 ]] && MAXCHILD="$2" 

    #Param 3 - File to be used as FIFO 
    FIFO="/tmp/defaultqueue" 
    [[ $# -gt 2 ]] && FIFO="$3" 

    #Number of seconds to keep the runner active when unused 
    TIMEOUT=5 

    runner(){ 
     #Associate file descriptor 3 to the FIFO 
     exec 3"$FIFO" 

     while read -u 3 -t $TIMEOUT line; do 
     #max child check 
     while [ `jobs | grep Running | wc -l` -ge "$MAXCHILD" ]; do 
      sleep 1 
     done 

     #exec in backgroud 
     (eval "$line")& 
     done 
     rm $FIFO 
    } 

    writer(){ 
     #fork if the runner is not running 
     lsof $FIFO >/dev/null || ($0 "QueueRunner" "$MAXCHILD" "$FIFO" &) 

     #send the command to the runner 
     echo "$COMMAND" > $FIFO 
    } 

    #Create the FIFO file 
    [[ -e "$FIFO" ]] || mkfifo "$FIFO" 

    #Start the runner if in the runner fork, else put the command in the queue 
    [[ "$COMMAND" == "QueueRunner" ]] && runner || writer