Bash: Multiple pour les boucles en arrière-plan

8

Est-ce la bonne façon de démarrer plusieurs traitements séquentiels en arrière-plan?

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

Tous jdoivent être traités les uns après les autres pour un certain temps i, mais tous idoivent être traités simultanément.

Controlé par radio
la source
Qu'entendez-vous par «bonne façon»?
Eran Ben-Natan
Principalement que cela fonctionne. Je manquais cela sur stackoverflow.
Contrôlé par radio
1
:-) Je demande parce que votre code fonctionne bien pour moi. Si par "voie correcte" vous entendez les meilleures pratiques, alors je mettrais la boucle interne dans une fonction ou même un fichier différent pour que ce soit plus clair
Eran Ben-Natan

Réponses:

8

La boucle extérieure que vous avez est essentiellement

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

Cela démarrerait dix instances simultanées de some_compound_commandl'arrière-plan. Ils seront lancés le plus rapidement possible, mais pas tout à fait "tous en même temps" (c'est-à-dire que si cela some_compound_commandprend très peu de temps, alors le premier peut bien finir avant que le dernier ne commence).

Le fait qu'il some_compound_commands'agisse d'une boucle n'est pas important. Cela signifie que le code que vous montrez est correct dans la mesure où les itérations de la jboucle interne s'exécuteront séquentiellement, mais toutes les instances de la boucle interne (une par itération de la iboucle externe ) seront démarrées simultanément.

La seule chose à garder à l'esprit est que chaque tâche d'arrière-plan s'exécutera dans un sous-shell. Cela signifie que les modifications apportées à l'environnement (par exemple, les modifications des valeurs des variables shell, les modifications du répertoire de travail actuel avec cd, etc.) dans une instance de la boucle interne ne seront pas visibles en dehors de ce travail d'arrière-plan particulier.

Ce que vous voudrez peut-être ajouter est une waitinstruction après votre boucle, juste pour attendre que tous les travaux en arrière-plan se terminent réellement, au moins avant la fin du script:

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

wait
Kusalananda
la source
3

Si vous avez GNU Parallel, vous feriez:

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

L'un des avantages est que la sortie de l'exécution parallèle run_commandsne se mélangera pas.

Ole Tange
la source