Comment utiliser le traitement multithread dans les scripts Bash - CloudSavvy IT
Agence web » Actualités du digital » Comment utiliser le traitement multithread dans les scripts Bash –

Comment utiliser le traitement multithread dans les scripts Bash –

Alexeï Mnogosmyslov/Shutterstock.com

La programmation multithread a toujours intéressé les développeurs pour augmenter les performances des applications et optimiser l’utilisation des ressources. Ce guide vous présentera les bases du codage multithread de Bash.

Quel est programmation multi-thread?

Une image vaut mille mots, et cela vaut quand il s’agit de montrer la différence entre la programmation à un seul fil (1) et la programmation multi-thread (> 1) dans Bash :

sleep 1
sleep 1 & sleep 1

(Dernière commande) Une simple commande d'une ligne à deux threads qui exécutera deux processus de veille en parallèle, un en arrière-plan

Notre première configuration de programmation multi-thread ou mini script one-liner n’aurait pas pu être plus simple ; dans la première ligne, nous dormons une seconde en utilisant le sleep 1 commander. En ce qui concerne l’utilisateur, un seul thread exécutait un seul sommeil d’une seconde.

Dans la deuxième ligne, nous avons deux commandes de veille d’une seconde. Nous les rejoignons en utilisant un & séparateur, qui n’agit pas seulement comme un séparateur entre les deux sleep commandes, mais aussi comme indicateur à Bash pour démarrer la première commande dans un thread d’arrière-plan.

Normalement, on terminerait une commande en utilisant un point-virgule (;). Cela exécuterait la commande et passerait ensuite à la commande suivante répertoriée derrière le point-virgule. Par exemple, exécuter sleep 1; sleep 1 prendrait un peu plus de deux secondes – exactement une seconde pour la première commande, une seconde pour la seconde, et une infime quantité de temps système pour chacune des deux commandes.

Cependant, au lieu de terminer une commande par un point-virgule, on peut utiliser d’autres terminateurs de commande que Bash reconnaît comme &, && et ||. Le && la syntaxe n’a aucun rapport avec la programmation multi-thread, elle fait simplement ceci ; procéder à l’exécution de la deuxième commande uniquement si la première commande a réussi. Le || est le contraire de && et exécutera la deuxième commande uniquement si la première commande a échoué.

Retour à la programmation multithread, en utilisant & car notre terminateur de commande lancera un processus d’arrière-plan exécutant la commande qui le précède. Il procède ensuite immédiatement à l’exécution de la commande suivante dans le shell actuel tout en laissant le processus d’arrière-plan (thread) s’exécuter par lui-même.

Dans la sortie de la commande, nous pouvons voir un processus d’arrière-plan en cours de démarrage (comme indiqué par [1] 445317445317 est l’ID de processus ou le PID du processus d’arrière-plan qui vient de démarrer et [1] est indiqué qu’il s’agit de notre premier processus d’arrière-plan) et qu’il est ensuite terminé (comme indiqué par [1]+ Done sleep 1).

Si vous souhaitez voir un exemple supplémentaire de gestion des processus en arrière-plan, veuillez consulter notre article sur l’automatisation et les scripts Bash (partie 3). De plus, Bash Process Termination Hacks peut être intéressant.

Prouvons maintenant que nous gérons effectivement deux sleep traite en même temps :

time sleep 1; echo 'done'
time $(sleep 1 & sleep 1); echo 'done'

Exécuter deux threads de veille en parallèle, avec un en arrière-plan, à l'aide d'un sous-shell

Ici, nous commençons notre sleep processus sous time et nous pouvons voir comment notre commande à thread unique a fonctionné pendant exactement 1,003 secondes avant que notre invite de ligne de commande ne soit renvoyée.

Cependant, dans le deuxième exemple, cela a pris à peu près le même temps (1,005 seconde) même si nous exécutions deux périodes (et processus) de sommeil, mais pas consécutivement. Encore une fois, nous avons utilisé un processus d’arrière-plan pour la première commande sleep, conduisant à une exécution (semi-)parallèle, c’est-à-dire multithread.

Nous avons également utilisé un wrapper de sous-shell ($(...)) autour de nos deux commandes sleep pour les combiner sous time. Comme nous pouvons le voir notre done la sortie montre en 1,005 secondes et donc les deux sleep 1 les commandes doivent avoir été exécutées simultanément. La très faible augmentation du temps de traitement global (0,002 seconde) est intéressante, ce qui s’explique facilement par le temps nécessaire pour démarrer un sous-shell et le temps nécessaire pour lancer un processus en arrière-plan.

Gestion des processus multithread (et en arrière-plan)

Dans Bash, le codage multithread implique normalement des threads d’arrière-plan à partir d’un script principal d’une ligne ou d’un script Bash complet. En substance, on peut considérer le codage multithread dans Bash comme le démarrage de plusieurs threads d’arrière-plan. Lorsque l’on commence à coder en utilisant plusieurs threads, il devient rapidement clair que de tels threads nécessitent généralement une certaine manipulation. Par exemple, prenons l’exemple fictif où nous démarrons cinq périodes (et processus) de sommeil simultanées dans un script Bash ;

#!/bin/bash

sleep 10 & 
sleep 600 & 
sleep 1200 & 
sleep 1800 & 
sleep 3600 &

Exécution de cinq threads de veille parallèles en arrière-plan à partir d'un script

Lorsque nous démarrons le script (après l’avoir rendu exécutable en utilisant chmod +x rest.sh), nous ne voyons aucune sortie ! Même si nous exécutons jobs (la commande qui affiche les tâches d’arrière-plan en cours), il n’y a pas de sortie. Pourquoi?

La raison en est que le shell qui a été utilisé pour démarrer ce script (c’est-à-dire le shell actuel) n’est pas le même shell (ni le même thread ; pour commencer à penser en termes de sous-shells en tant que threads en eux-mêmes) qui a exécuté le sommeil réel commandes ou les a placées en arrière-plan. C’est plutôt le (sous)shell qui a été lancé lorsque ./rest.sh a été exécuté.

Modifions notre script en ajoutant jobs à l’intérieur du script. Cela garantira que jobs est exécuté à partir du (sous)shell où il est pertinent, le même que celui où les périodes (et les processus) de sommeil ont été démarrées.

Ajout de la commande jobs dans le script

Cette fois, nous pouvons voir la liste des processus d’arrière-plan en cours de démarrage grâce à la jobs commande à la fin du script. Nous pouvons également voir leurs PID (Process Identifiers). Ces PID sont très importants lorsqu’il s’agit de gérer et de gérer les processus d’arrière-plan.

Une autre façon d’obtenir l’identificateur de processus en arrière-plan consiste à l’interroger immédiatement après avoir placé un programme/processus en arrière-plan :

#!/bin/bash

sleep 10 & 
echo ${!}
sleep 600 & 
echo ${!}
sleep 1200 & 
echo ${!}
sleep 1800 & 
echo ${!}
sleep 3600 &
echo ${!}

Interrogation du PID (Process ID) du dernier processus d'arrière-plan à démarrer à l'aide de ${!}

Semblable à notre jobs commande (avec de nouveaux PID maintenant que nous avons redémarré notre rest.sh script), grâce au Bash ${!} variable étant renvoyée, nous allons maintenant voir les cinq PID s’afficher presque immédiatement après le démarrage du script : les différents processus de veille ont été placés dans les threads d’arrière-plan les uns après les autres.

The wait Command

Une fois que nous avons commencé nos processus d’arrière-plan, nous n’avons rien d’autre à faire que d’attendre qu’ils soient terminés. Cependant, lorsque chaque processus d’arrière-plan exécute une sous-tâche complexe et que nous avons besoin du script principal (qui a démarré les processus d’arrière-plan) pour reprendre l’exécution lorsqu’un ou plusieurs des processus d’arrière-plan se terminent, nous avons besoin de code supplémentaire pour gérer cela.

Développons maintenant notre script avec le wait commande pour gérer nos threads d’arrière-plan :

#!/bin/bash

sleep 10 & 
T1=${!}
sleep 600 & 
T2=${!}
sleep 1200 & 
T3=${!}
sleep 1800 & 
T4=${!}
sleep 3600 &
T5=${!}

echo "This script started 5 background threads which are currently executing with PID's ${T1}, ${T2}, ${T3}, ${T4}, ${T5}."
wait ${T1}
echo "Thread 1 (sleep 10) with PID ${T1} has finished!"
wait ${T2}
echo "Thread 2 (sleep 600) with PID ${T2} has finished!"

Ici, nous avons étendu notre script avec deux wait commandes qui attendent que le PID attaché aux premier et deuxième threads se termine. Après 10 secondes, notre premier thread existe et nous en sommes informés. Étape par étape, ce script effectuera les opérations suivantes : démarrer cinq threads presque en même temps (bien que le démarrage des threads lui-même soit toujours séquentiel et non parallèle) où chacun des cinq sleeps’exécutera en parallèle.

Le script principal signale ensuite (séquentiellement) le thread créé et attend ensuite que l’ID de processus du premier thread se termine. Lorsque cela se produit, il signalera séquentiellement la fin du premier thread et commencera à attendre la fin du deuxième thread, etc.

Utiliser les idiomes Bash &, ${!} et le wait La commande nous donne une grande flexibilité lorsqu’il s’agit d’exécuter plusieurs threads en parallèle (en tant que threads d’arrière-plan) dans Bash.

Emballer

Dans cet article, nous avons exploré les bases des scripts multithreads de Bash. Nous avons introduit l’opérateur de processus d’arrière-plan (&) en utilisant des exemples faciles à suivre montrant à la fois des threads simples et multithreads sleep commandes. Ensuite, nous avons examiné comment gérer les processus d’arrière-plan via les idiomes Bash couramment utilisés ${!} et wait. Nous avons également exploré le jobs commande pour voir les threads/processus en cours d’exécution.

Si vous avez aimé lire cet article, jetez un œil à notre article Bash Process Termination Hacks. Prendre plaisir!

★★★★★