2013-06-25 17 views
20

Ci sono state alcune domande simili, ma il mio problema non è "eseguire diversi programmi in parallelo" - cosa che può essere banalmente fatta con parallel o xargs.Come eseguire una determinata funzione in Bash in parallelo?

Ho bisogno di parallelizzare le funzioni di Bash.

Immaginiamo codice come questo:

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
    # some processing in here - 20-30 lines of almost pure bash 
    done 
done 

Alcuni del trattamento richiede chiamate a programmi esterni.

Mi piacerebbe eseguire alcune (4-10) attività, ciascuna in esecuzione per diversi $i. numero totale di elementi in lista è $> 500.

so di poter mettere l'intera for j ... done loop in script esterno, e basta chiamare questo programma in parallelo, ma è possibile fare a meno di dividere la funzionalità tra due programmi separati ?

+0

Provare a utilizzare le funzioni. O qualcosa come 'var1 = \' ls && pwd && ls && pwd & \ '' nel tuo ciclo. –

+0

Sì, ma non voglio eseguire * tutte * le iterazioni contemporaneamente. Mi piacerebbe avere 4 processi di lavoro simultanei, e se qualcuno di loro finisce, ne inizi uno nuovo. Un po 'come: 'cat work_params | xargs -L1 -P4 do_bit_of_work' funziona. –

+0

Hmmm ... 4 lavoratori. Immagino che dovrai creare una specie di semafori allora. E sondaggi periodicamente. –

risposta

10

Modifica: Si prega di considerare Ole's answer invece.

Invece di uno script separato, è possibile inserire il codice in una funzione bash separata. È quindi possibile esportarlo, ed eseguirlo tramite xargs:

#!/bin/bash 
dowork() { 
    sleep $((RANDOM % 10 + 1)) 
    echo "Processing i=$1, j=$2" 
} 
export -f dowork 

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
     printf "%s\0%s\0" "$i" "$j" 
    done 
done | xargs -0 -n 2 -P 4 bash -c 'dowork "[email protected]"' -- 
+0

Potrebbe funzionare, grazie. –

32

sem fa parte di GNU in parallelo ed è fatto per questo tipo di situazione.

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
     # some processing in here - 20-30 lines of almost pure bash 
     sem -j 4 dolong task 
    done 
done 

Se ti piace la migliore funzione GNU parallelo può fare il doppio ciclo for in una sola volta:

dowork() { 
    echo "Starting i=$1, j=$2" 
    sleep 5 
    echo "Done i=$1, j=$2" 
} 
export -f dowork 

parallel dowork ::: "${list[@]}" ::: "${other[@]}" 
+3

Fantastico. Molto più agevole del mio suggerimento. –

+2

Questo non funziona (più?) (GNU parallelo 20.160.722), uscite "/ bin/bash: DoWork: command not found".. – jamshid

+1

@jamshid Ti ricordi 'export -f dowork'? Se sì, allora potresti aver trovato un bug che appare sul tuo sistema. Come soluzione: prova 'env_parallel' invece di' parallel'. –

0

soluzione per l'esecuzione su più righe comandi in parallelo:

for i in "${list[@]}" 
do 
    for j in "${other[@]}" 
    do 
     test "$(jobs | wc -l)" -ge 8 && wait -n || true 
     (
      your 
      multi-line 
      commands 
      here 
     ) & 
    done 
done 

Se ci sono 8 lavori bash già in esecuzione, wait attenderà che sia completato almeno un lavoro. Se/quando ci sono meno lavori, ne inizia di nuovi in ​​modo asincrono.

I vantaggi di questo approccio:

  1. E 'molto facile per i comandi multi-linea. Tutte le variabili vengono automaticamente "catturate" nella portata, non c'è bisogno di passarle come argomenti
  2. È relativamente veloce. Confronta questo, ad esempio, in parallelo (sto citando ufficiale man):

    parallelo è lento all'avvio - circa 250 ms la prima volta e 150 ms dopo.

  3. Ha solo bisogno di bash per funzionare.

Svantaggi:

  1. C'è la possibilità che ci fossero 8 posti di lavoro quando li abbiamo contati, ma meno quando abbiamo iniziato in attesa. (Succede se un lavoro termina in quei millisecondi tra i due comandi.) Questo può renderci wait con meno lavori del necessario.Tuttavia, riprenderà quando almeno un lavoro sarà completato, o immediatamente se ci sono 0 lavori in esecuzione (wait -n uscite immediatamente in questo caso).
  2. Altamente improbabile, ma se si utilizza il controllo dei job bash (&) per altri scopi all'interno dello stesso ciclo, le cose possono funzionare non come previsto.
Problemi correlati