Bash: multiplo per loop in background


8

È questo il modo corretto di avviare più processi sequenziali in background?

for i in {1..10}; do
    for j in {1..10}; do
        run_command $i $j;
    done &
done;

Tutti jdovrebbero essere elaborati uno dopo l'altro per un dato i, ma tutti idovrebbero essere elaborati contemporaneamente.


Cosa intendi con "modo corretto"?
Eran Ben-Natan,

Principalmente che funziona. Mi mancava questo su StackOverflow.
Radio Controlled

1
:-) Sto chiedendo perché il tuo codice funziona bene per me. Se per "modo corretto" intendi le migliori pratiche, metterei il ciclo interno in una funzione o anche in un file diverso, quindi è più chiaro
Eran Ben-Natan,

Risposte:


8

Il ciclo esterno che hai è fondamentalmente

for i in {1..10}; do
    some_compound_command &
done

Ciò darebbe inizio a dieci istanze simultanee di some_compound_commandin background. Saranno avviati il più velocemente possibile, ma non abbastanza "tutti allo stesso tempo" (cioè se some_compound_commandprende molto poco tempo, poi la prima può ben finire prima delle ultime si comincia).

Il fatto che some_compound_commandsi tratti di un ciclo non è importante. Ciò significa che il codice che mostri è corretto in quanto le iterazioni del jciclo interno verranno eseguite in sequenza, ma tutte le istanze del ciclo interno (una per iterazione del iciclo esterno ) verranno avviate contemporaneamente.

L'unica cosa da tenere a mente è che ogni processo in background verrà eseguito in una subshell. Ciò significa che le modifiche apportate all'ambiente (ad esempio modifiche ai valori delle variabili della shell, modifiche della directory di lavoro corrente con cd, ecc.) In un'istanza del ciclo interno non saranno visibili al di fuori di quel particolare lavoro in background.

Quello che potresti voler aggiungere è waitun'istruzione dopo il tuo ciclo, solo per aspettare che tutti i lavori in background finiscano effettivamente, almeno prima che lo script termini:

for i in {1..10}; do
    for j in {1..10}; do
        run_command "$i" "$j"
    done &
done

wait

3

Se hai GNU Parallel dovresti:

parallel -j0 'for j in {1..10}; do run_command {} $j; done' ::: {1..10}

Uno dei vantaggi è che l'output della corsa parallela run_commandsnon si mescolerà.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.