Parallélisation d'une boucle for


9

Je veux paralléliser les forboucles du code suivant. Comment faire ça?

#!/bin/bash
N=$1 
n=$2
for (( i=1; i<=$N; i++ )); do
  min=100000000000000  //set min to some garbage value
  for (( j=1; j<=$n; j++ )); do
    val=$(/path/to/a.out)
    val2=`echo $val | bc`  

      if (( $val2 < $min )); then
        min=$val2; 
      fi
  done
  arr=("${arr[@]}" "$min")
done


Réponses:


10
#!/bin/bash
# set -x # debug version
N=${1:-123}
n=${2:-45}
workers=${workers:-${3:-10}}
((workers < 1)) && ((workers = 1))
((workers > 20)) && ((workers = 20))

((min=100000000000000))  #set min to some garbage value

work() {
  for i in ${*}; do
    for (( j=1; j<=${n}; j++ )); do
      val=$(/path/to/a.out)
      val2=$(echo ${val} | bc)
      (( val2 < min )) && (( min = val2 ));
    done
    echo ${min}
    # # debug version
    # echo ${i} ${j} ${min}
  done
}

# --
arr=($(
  seq ${N} | xargs -n$[N/workers + 1] | while read i; do
    work ${i} &
  done
  wait
))
echo ${arr[*]}
# --

# # debug version
# seq ${N} | xargs -t -n$[N/workers + 1] | while read i; do
#  work ${i} &
# done
# wait

Utilisez toujours des travailleurs lorsque vous générez un nombre paramétré de processus et limitez le nombre maximal de travailleurs pouvant apparaître .

xargs -n | while read est un moyen simple d'itérer des listes par lots.

  • seq crée une liste de nombres de 1 à N.
  • xargs -n divise cette liste en N / travailleurs + 1 lots.
    • Par exemple, N = 100 travailleurs = 10 produira 10 lignes de jusqu'à 11 numéros de 1 à 100.
  • while read i lit chaque ligne de nombres.
  • work ${i} &appelle simplement la workfonction avec un ${i}lot de nombres.

Pour déboguer, j'ai ajouté du code de débogage commenté. Remplacez simplement le echopar la version de débogage et le code entre # --par sa version de débogage et vous pouvez voir comment cela fonctionne sur des lots. Décommentez set -xpour une sortie de débogage plus détaillée que vous voudrez peut-être rediriger vers un fichier.

Exécutez simplement la version de débogage avec différents paramètres pour voir comment elle fonctionne:

parallel.sh 223 5 1
parallel.sh 223 5 5
parallel.sh 223 5 10
parallel.sh 223 5 20

Avertissement: ce code ne synchronise pas la minvaleur entre les processus de travail. L'obtention de la valeur minimale n'est pas un exercice horrible. Cela fera probablement:

parallel.sh 223 5 20 | tr ' ' '\n' | sort -n | head -1

Ou ajoutez simplement la même chose au script lui-même:

echo ${arr[*]} | tr ' ' '\n' | sort -n | head -1

Pouvez-vous expliquer le code? Pour moi, la façon dont vous avez utilisé les threads de travail ici n'est pas claire.
RIchard Williams

@prasenjit Done. J'espère que c'est utile.
nicerobot

8

Utilisation de GNU Parallel:

#!/bin/bash

N=$1
n=$2

arr=($(
# Generate all combinations of 1..n and 1..N
parallel -k --tag /path/to/a.out {1} {2} '|' bc :::: <(seq $N) <(seq $n) |
  perl -ane 'BEGIN{$min=1e30} $last||=$F[0]; if($F[0] != $last) {print $min,"\n";$min=1e30;$last=$F[0]} $min = $F[2]<$min ? $F[2] : $min; END {print $min,"\n"}'
))
echo ${arr[*]}

Cela fonctionnera /path/to/a.outsur chaque CPU. La sortie sera comme:

1 1 19269
1 2 6158
1 3 2794
1 4 25104
2 1 13160
2 2 32683
2 3 12535
2 4 15197
3 1 8228
3 2 7673
3 3 8428
3 4 24463

Le script perl regarde la première colonne et trouve le minimum dans la 3ème colonne qui a la même première colonne.

Vous pouvez installer GNU Parallel simplement en:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel

Regardez les vidéos d'introduction pour en savoir plus: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1


Le lien dans votre dernier paragraphe renvoie à une page Facebook qui indique au visiteur qu'il a gagné un cadeau exclusif (publicité ou arnaque). Il n'y a pas de vidéos. Vous devez le supprimer.
Marco
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.