Comment utiliser le traitement multithread dans les scripts bash

Contenu

chat jouant avec du fil

La planification multi-thread a toujours été dans l'intérêt des développeurs pour augmenter les performances des applications et maximiser l'utilisation des ressources.. Ce guide vous présentera les bases de l'encodage multithread Bash.

Qu'est que c'est programmation multiprocessus?

Une image vaut mieux que mille mots, et c'est valable quand il s'agit de montrer la différence entre programmer un seul (1) planification des threads et multi-threads (> 1) en bas:

dormir 1
dormir 1 & dormir 1

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

Notre premier mini script à une seule ligne ou configuration de planification multi-thread n'aurait pas pu être plus simple; en première ligne, nous avons dormi une seconde en utilisant le sleep 1 commander. Concernant l'utilisateur, un seul thread exécutait un seul rêve d'une seconde.

Sur la deuxième ligne, nous avons deux commandes de suspension d'une seconde. Nous les rejoignons à l'aide d'un & séparateur, qui agit non seulement comme un séparateur entre les deux sleep commandes, mais aussi comme invite Bash pour démarrer la première commande dans un fil d'arrière-plan.

Régulièrement, on terminerait une commande en utilisant un point-virgule (;). Ce faisant, la commande serait exécutée et alors seulement serait-elle passée à la prochaine commande qui apparaît après le point-virgule. Par exemple, fonctionnement sleep 1; sleep 1 cela prendrait un peu plus de deux secondes: exactement une seconde pour la première commande, une seconde pour la seconde et une petite quantité de surcharge système pour chacune des deux commandes.

Malgré cela, au lieu de terminer une commande par un point-virgule, vous pouvez utiliser d'autres terminateurs de commande que Bash reconnaît comme &, && et ||. Les && la syntaxe n'a rien à voir avec la programmation multithread, fais juste ça; procéder à l'exécution de la deuxième commande uniquement si la première commande a réussi. Les || C'est le contraire de && et il n'exécutera la deuxième commande que si la première commande a échoué.

Revenir à la programmation multithread, à l'aide de & puisque notre terminateur de commande lancera une procédure d'arrière-plan en exécutant la commande qui la précède. Il procède ensuite immédiatement à l'exécution de la commande suivante dans le shell actuel tout en laissant la procédure d'arrière-plan (salut) courir tout seul.

Dans la sortie de la commande, nous pouvons voir qu'une procédure démarre en arrière-plan (comme indiqué [1] 445317445317 est l'ID ou le PID de la procédure d'arrière-plan nouvellement démarrée, et [1] il est indiqué qu’il s’agit de notre première procédure de fond) et par la suite résilié (comme indiqué [1]+ Done sleep 1).

Si vous souhaitez voir un exemple supplémentaire de gestion des processus en arrière-plan, voir notre article Bash Automation and Scripting Basics (Partie 3). En même temps, Les astuces de résiliation de la procédure Bash peuvent être intéressantes.

Maintenant, montrons que nous en courons effectivement deux sleep processus en même temps:

le sommeil de temps 1; echo 'done'
time $(dormir 1 & dormir 1); écho 'fait'

Exécuter deux threads de suspension en parallèle, avec un en arrière-plan, en utilisant une sous-couche

Ici, nous commençons notre sleep procédure basse time et nous pouvons voir comment notre commande à thread unique a fonctionné exactement 1.003 secondes avant que l'invite de ligne de commande ne soit renvoyée.

Malgré cela, dans le deuxième exemple, a pris à peu près le même temps (1,005 secondes) même si nous courions deux périodes (et processus) suspension, même si pas consécutivement. Encore une fois, nous utilisons une procédure d'arrière-plan pour la première commande de suspension, menant à une exécution (semi) parallèle, Autrement dit, multiprocessus.

Nous utilisons également un conteneur de sous-couche ($(...)) autour de nos deux commandes de rêve pour les combiner sous time. Comment pouvons-nous voir notre done la sortie est affichée dans 1.005 secondes et, pour cela, les deux sleep 1 les commandes doivent avoir été exécutées simultanément. Intéressant est la très faible augmentation du temps de traitement total (0,002 secondes) ce qui s'explique facilement par le temps qu'il faut pour démarrer une sous-couche et le temps qu'il faut pour démarrer une procédure d'arrière-plan.

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

En bas, l'encodage multithread impliquera régulièrement des threads d'arrière-plan à partir d'un script principal d'une ligne ou d'un script bash complet. Essentiellement, on peut considérer l'encodage multithread dans Bash comme le démarrage de plusieurs threads d'arrière-plan. Quand on commence à coder en utilisant plusieurs threads, il devient rapidement clair que de tels threads nécessiteront généralement une certaine manipulation. Par exemple, prenons l'exemple fictif où nous commençons cinq périodes concurrentes (et processus) de sommeil dans un script Bash;

#!/bin/bash

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

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

Lorsque nous démarrons le script (après l’avoir rendu exécutable à l’aide de chmod +x rest.sh), nous ne voyons pas d’issue !! Même si nous courons jobs (la commande qui affiche les travaux en arrière-plan en cours), pas d’issue. Parce que?

La raison en est que le shell qui a été utilisé pour démarrer ce script (Autrement dit, le shell actuel) n’est pas la même coquille (ni le même fil; commencer à penser en termes de sous-couches comme des fils en eux-mêmes) qui a exécuté le rêve royal. commandes ou les a placées en arrière-plan. C'était plutôt le (sous) shell qui a commencé quand ./rest.sh a été exécuté.

Modifions notre script en ajoutant jobs à l'intérieur du script. Cela garantira que jobs s'exécute à l'intérieur du (sous) coquille le cas échéant, le même dans lequel les périodes ont commencé (et processus) du sommeil.

Ajouter une commande de tâches dans le script

Cette fois, nous pouvons voir la liste des processus d'arrière-plan qui démarrent grâce à jobs commande à la fin du script. Nous pouvons également voir leurs PID (identifiants de procédure). 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'ID de procédure d'arrière-plan est de l'interroger immédiatement après avoir placé un programme / procédure de fond:

#!/bin/bash

sleep 10 & 
écho ${!}
dormir 600 & 
écho ${!}
dormir 1200 & 
écho ${!}
dormir 1800 & 
écho ${!}
dormir 3600 &
écho ${!}

Consulter le PID (Identifiant du processus) du dernier processus d'arrière-plan à démarrer avec $ {!}

Semblable à notre jobs commander (avec de nouveaux PID maintenant lorsque nous redémarrons notre rest.sh scénario), grâce au bash ${!} Lorsque la variable est répétée, nous verrons maintenant que les cinq PID sont affichés presque immédiatement après le démarrage du script: plusieurs processus de suspension ont été placés dans des 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 qu'attendre qu'ils finissent. Malgré cela, lorsque chaque procédure d'arrière-plan exécute une sous-tâche complexe, et nous avons besoin du script principal (qui a démarré les processus d'arrière-plan) 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=${!}
dormir 600 & 
T2=${!}
dormir 1200 & 
T3 = ${!}
dormir 1800 & 
T4 = ${!}
dormir 3600 &
T5 = ${!}

écho "Ce script a commencé 5 threads d'arrière-plan qui s'exécutent actuellement avec les PID ${T1}, ${T2}, ${T3}, ${T4}, ${T5}."
attendre ${T1}
écho "Fil 1 (dormir 10) avec PID ${T1} avoir fini!"
attendre ${T2}
écho "Fil 2 (dormir 600) avec PID ${T2} avoir fini!"

Ici, nous étendons notre script avec deux wait commandes qui attendent que le PID attaché aux premier et deuxième threads se termine. Après que 10 secondes, notre premier fil existe et nous en sommes avertis. Pas à pas, ce script fera ce qui suit: démarrer cinq threads presque en même temps (même si le début des threads lui-même est toujours séquentiel et non parallèle) où chacun des cinq sleepfonctionnera en parallèle.

Après, les principaux rapports de script (séquentiellement) sur le fil créé et, ensuite, attendre que l'identifiant de procédure du premier thread se termine. Quand ça arrive, rapportera 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 (comme fils de fond) en bas.

Fin

Dans ce billet, Nous explorons les bases du script multithread Bash. Introduction de l'opérateur de procédure d'arrière-plan (&) en utilisant quelques exemples faciles à suivre montrant à la fois un filetage simple et un filetage multiple sleep commandes. Ensuite, nous discutons de la façon de gérer les processus d'arrière-plan à l'aide des idiomes bash couramment utilisés. ${!} et wait. Nous explorons également le jobs commande pour afficher l'exécution du thread / Processus en arrière-plan.

Si vous avez aimé lire cet article, jetez un œil à notre article Bash Procedure Termination Hacks.

Abonnez-vous à notre newsletter

Nous ne vous enverrons pas de courrier SPAM. Nous le détestons autant que vous.