2017-08-11 4 views
0

J'ai le script bash suivant, qui démarre un programme plusieurs fois en parallèle et passe une variable de contrôle à chaque exécution. Le programme utilise plusieurs ressources, donc après avoir été démarré 10 fois en parallèle, je veux attendre jusqu'à ce que les 10 derniers démarrés soient terminés.Attente des 10 derniers travaux démarrés en parallèle pour terminer dans bash

Je le fais actuellement très grossièrement, en attendant 10 cycles d'attente le plus longtemps possible pour que 10 programmes démarrés en parallèle soient terminés.

Existe-t-il un moyen simple d'implémenter ce comportement?

steps=$((500/20)) 
echo $steps 
START=0 

for((i=START;i < steps; i++)) 
do 
     for((j=START;j < steps;j++)) 
     do 
       for((k=START;k < steps;k++)) 
       do 
         n=$(($j*steps +$k)) 
         idx=$(($i*$steps*$steps + $n)) 


         if ! ((idx % 10)); then 
           echo "waiting for the last 10 programs" 
           sleep 10 
         else 
           ./someprogram $idx & 
         fi 
       done 
     done 
done 
+0

Si vous souhaitez suivre si les programmes réussi ou échoué, vous voudrez stocker leurs PID. Un mappage de tableau associatif entre PID et 'idx' est particulièrement utile, car cela vous permet de savoir quels' idx's ont réussi et échoué. –

+0

BTW, cette approche dans son ensemble est généralement assez inefficace - vous avez généralement un tas de temps processeur gaspillé entre le moment où le premier programme dans un lot se termine et quand le dernier fait. Mieux vaut utiliser quelque chose comme 'pour ((k = début; k

+0

@CharlesDuffy Merci, j'ai vu cet article et je ne suis pas tout à fait sûr qu'il est relatable pour mon cas en raison de l'utilisation d'un appareil asynchrone, qui repose sur le temps d'attente pour terminer les travaux. Cependant, votre réponse fournit-elle déjà l'attente du programme ou est-ce juste pour commencer? – Kev1n91

Répondre

2

Eh bien, puisque vous avez déjà un code en place pour vérifier la 10e itération (idx % 10), le wait semble parfait builtin. A partir de la documentation:

wait: wait [-n] [id ...]

[...] Attend pour chaque processus identifié par un ID, qui peut être un ID de processus ou une spécification de travail et transmet son état de cessation d'emploi. Si ID n'est pas donné, attend tous les processus enfants actuellement actifs et l'état de retour est zéro.

Ainsi, en wait ing chaque fois idx % 10 == 0, vous attendent en fait pour tous les processus enfants précédents à la fin. Et si vous ne générez rien d'autre que someprogram, alors vous attendez que ces derniers (jusqu'à 10) soient terminés.

Votre script avec wait:

#!/bin/bash 

steps=$((500/20)) 
START=0 

for ((i=START; i<steps; i++)); do 
    for ((j=START; j<steps; j++)); do 
     for ((k=START; k<steps; k++)); do 
      idx=$((i*steps*steps + j*steps + k)) 

      if ! ((idx % 10)); then 
       wait 
      else 
       ./someprogram $idx & 
      fi 
     done 
    done 
done 

En outre, notez que vous ne devez pas utiliser $var (préfixe dollar) à l'intérieur d'expansion arithmétique $((var+1)).


Je suppose au-dessus de votre script actuel fait un peu un traitement supplémentaire avant d'appeler someprogram, mais si tout ce que vous avez besoin est d'appeler someprogram sur les index consécutifs, 10 cas à un moment, vous pouvez envisager d'utiliser xargs ou GNU parallel.

Par exemple, avec xargs:

seq 0 1000 | xargs -n1 -P10 ./someprogram 

ou, avec des arguments supplémentaires pour someprogram:

seq 0 1000 | xargs -n1 -P10 -I{} ./someprogram --option --index='{}' someparam 

Avec GNU parallel:

seq 0 1000 | parallel -P10 ./someprogram '{}' 

seq 0 1000 | parallel -P10 ./someprogram --option --index='{}' someparam 
+0

que vous en fait, je dois juste changer le code de "dormir 10" à "attendre" – Kev1n91

+0

Oui, exactement cela. :) – randomir

+1

J'ai ajouté quelques alternatives, si cela s'applique à votre cas d'utilisation. – randomir