AllInfo

Comment utiliser le traitement multithread dans les scripts Bash

Aleksey Mnogosmyslov/Shutterstock.com

Multi -La programmation threadée 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.

Qu'est-ce que la programmation multithread ?

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 à plusieurs fils (>1) dans Bash :

sleep 1 sleep 1 &amp ; dormir 1

Notre première configuration de programmation multithread ou mini script one-liner n'aurait pas pu être plus simple ; dans la première ligne, nous dormons pendant une seconde en utilisant la commande sleep 1. 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 commandes sleep, mais aussi comme un 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 le sommeil 1 ; le sommeil 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 surcharge système pour chacune des deux commandes.

Cependant, au lieu de terminer une commande par un point-virgule, on peut utiliser d'autres fins 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é.

Revenir à 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 de lui-même.

Publicité

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

Si vous souhaitez afficher un exemple supplémentaire de gestion de processus en arrière-plan, veuillez consulter notre Bash Automation and Scripting Basics (Part 3) article. De plus, Bash Process Termination Hacks peut être intéressant.

Montrons maintenant que nous exécutons effectivement deux processus de veille en même temps :

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

Ici, nous commençons notre processus de veille dans le temps et nous pouvons voir comment notre commande à thread unique s'est exécutée pendant exactement 1,003 secondes avant notre commande l'invite de ligne a été 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.

Publicité

Nous avons également utilisé un wrapper de sous-shell ($(…)) autour de nos deux commandes sleep pour les combiner dans le temps. Comme nous pouvons le voir, notre sortie terminée s'affiche en 1,005 seconde et les deux commandes sleep 1 doivent donc avoir été exécutées simultanément. Intéressant est la très faible augmentation du temps de traitement global (0,002 seconde) 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 évident que de tels threads nécessitent généralement une certaine manipulation. Par exemple, prenons l'exemple fictif où nous commençons cinq périodes (et processus) de sommeil simultanés dans un script Bash ;

#!/bin/bash sleep 10 & dormir 600 & dormir 1200 & dormir 1800 & dormir 3600 &

Lorsque nous démarrons le script (après l'avoir rendu exécutable à l'aide de chmod +x rest.sh), nous ne voyons aucun production! Même si nous exécutons des tâches (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 et par eux-mêmes) qui a exécuté le sommeil réel commandes ou les a placées en arrière-plan. C'était plutôt le (sous)shell qui a été lancé lors de l'exécution de ./rest.sh.

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

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

Publicité

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

#!/bin/bash sleep 10 & echo ${!} sommeil 600 & echo ${!} sommeil 1200 & echo ${!} sommeil 1800 & echo ${!} sommeil 3600 & echo ${!}

Semblable à notre commande jobs (avec de nouveaux PID maintenant que nous avons redémarré notre script rest.sh), grâce à la variable Bash ${!} en écho, nous verrons maintenant 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.

La commande wait

Une fois que nous avons démarré notre arrière-plan processus, nous n'avons plus qu'à 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 la commande wait pour gérer nos threads d'arrière-plan :

#!/bin/bash sleep 10 & T1=${!} sommeil 600 & T2=${!} sommeil 1200 & T3=${!} sommeil 1800 & T4=${!} sommeil 3600 & T5=${!} echo “Ce script a démarré 5 threads d'arrière-plan qui s'exécutent actuellement avec les PID ${T1}, ${T2}, ${T3}, ${T4}, ${T5}.” wait ${T1} echo “Le thread 1 (sommeil 10) avec le PID ${T1} est terminé !” wait ${T2} echo “Le thread 2 (sleep 600) avec le PID ${T2} est terminé !”

Ici, nous avons étendu notre script avec deux commandes wait 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 sommeils s'exécutera en parallèle.< /p>

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 que le deuxième thread se termine, etc.

Publicité

En utilisant les idiomes Bash &, ${!} et le La commande wait 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.

Conclusion

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

Si vous avez aimé lire cet article, consultez notre article Bash Process Termination Hacks.

Exit mobile version