web-dev-qa-db-fra.com

Exécution d'un script shell en parallèle

J'ai un script shell qui 

  1. mélange un grand fichier texte (6 millions de lignes et 6 colonnes) 
  2. trie le fichier en fonction de la première colonne
  3. génère 1000 fichiers 

Donc, le pseudocode ressemble à ceci 

file1.sh 

#!/bin/bash
for i in $(seq 1 1000)
do

  Generating random numbers here , sorting  and outputting to file$i.txt  

done

Existe-t-il un moyen d'exécuter ce script Shell dans parallel pour exploiter pleinement les processeurs multicœurs?

Pour le moment, ./file1.sh s'exécute en séquence de 1 à 1000 exécutions et il est très lent.

Merci de votre aide.

41
Tony

Vérifiez bash subshells , ils peuvent être utilisés pour exécuter des parties d’un script en parallèle.

Je n'ai pas testé cela, mais cela pourrait être un début:

#!/bin/bash
for i in $(seq 1 1000)
do
   ( Generating random numbers here , sorting  and outputting to file$i.txt ) &
   if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells.
done
wait
42
Anders Lindahl

Une autre façon très pratique de faire cela est avec gnu parallel , qui vaut bien une installation si vous ne l'avez pas déjà. c'est inestimable si les tâches ne prennent pas nécessairement la même quantité de temps. 

seq 1000 | parallel -j 8 --workdir $PWD ./myrun {}

va lancer ./myrun 1, ./myrun 2, etc., en s'assurant que 8 tâches à la fois sont en cours d'exécution. Il peut également prendre des listes de nœuds si vous souhaitez exécuter plusieurs nœuds à la fois, par exemple dans un travail PBS; Nos instructions à nos utilisateurs pour savoir comment procéder sur notre système sont ici

Mis à jour pour ajouter: Vous voulez vous assurer que vous utilisez gnu-parallel, pas l'utilitaire plus limité du même nom qui est inclus dans le paquetage moreutils (l'histoire divergente des deux est décrite ici .)

84
Jonathan Dursi

Pour que les choses fonctionnent en parallèle, utilisez '&' à la fin d'une commande Shell pour l'exécuter en arrière-plan. wait attendra par défaut (c'est-à-dire sans arguments) que tous les processus en arrière-plan soient terminés. Alors, lancez peut-être 10 en parallèle, puis attendez, puis faites-en dix de plus. Vous pouvez le faire facilement avec deux boucles imbriquées.

13
Tony Delroy

Il existe une liste complète de programmes pouvant exécuter des tâches en parallèle à partir d'un shell, qui inclut même des comparaisons entre eux, dans la documentation de GNU parallèle. Il existe de très nombreuses solutions. Une autre bonne nouvelle est qu’ils sont probablement assez efficaces pour la planification des travaux, de sorte que tous les cœurs/processeurs restent occupés en permanence.

9
Eric O Lebigot

Il existe un programme simple et portable qui fait cela pour vous: PPSS . PPSS planifie automatiquement les travaux pour vous, en vérifiant le nombre de cœurs disponibles et en lançant un autre à chaque fois.

4
Eric O Lebigot
IDLE_CPU=1
NCPU=$(nproc)

int_childs() {
    trap - INT
    while IFS=$'\n' read -r pid; do
        kill -s SIGINT -$pid
    done < <(jobs -p -r)
    kill -s SIGINT -$$
}

# cmds is array that hold commands
# the complex thing is display which will handle all cmd output
# and serialized it correctly

trap int_childs INT
{
    exec 2>&1
    set -m

    if [ $NCPU -gt $IDLE_CPU ]; then
        for cmd in "${cmds[@]}"; do
            $cmd &
            while [ $(jobs -pr |wc -l) -ge $((NCPU - IDLE_CPU)) ]; do
                wait -n
            done
        done
        wait

    else
        for cmd in "${cmds[@]}"; do
            $cmd
        done
    fi
} | display
0
Zakaria