[gull] Truc et astuces: multithread en bash

felix felix at f-hauri.ch
Tue Dec 29 12:48:40 CET 2020


On Mon, Dec 28, 2020 at 11:29:41PM +0100, Daniel Cordey wrote:
> On 28/12/2020 21:44, felix wrote:
> > Du point de vue du script lui même, il converse *effectivement* avec 
> > au moins deux thread indépendant: Les pings et l'utilisateur
> ..
> Tu fais un fork, suivit d'un exec du code /usr/bin/ping. Donc un autre PID
> -> autre process -> Pas un thread !
Oui, je fais un fork (dans ce cas), mais le script, lui, converse avec
le ${fd}. De ce point de vue, il s'agit d'un flux indépendant de l'entrée
standard.

J'aurrai pu écrire:

  for i in {1..255};do
     exec {fd[i]}<>/dev/tcp/192.168.1.$i/22  # Ceci n'est pas un fork!
  done
  declare -p fd
  l=10
  while ((l--)) && ! read -t .5 -rsn 1 foo;do
      for i in ${!fd[@]} ;do
           read -t 0 -u ${fd[i]} &&
               read -u ${fd[i]} line && echo 192.168.1.$i: $line
      done
  done

Du point de vue du script bash, cela revient au même: plusieurs fils
de discutions à gérer indépendament.

Dans le cas de mon script qui utilise ghostscript, je parallélise
plusieurs commandes graphiques en utilisant (du point de vue du script)
plusieurs $fd différents, afin de paralléliser les opérations de
conversion, tout en évitant la sur-occupation du disque.
Bon, puisqu'on en est là, je poste un bout de mon script (Il n'est pas
abouti, fait pour l'instant 125 lignes)

    73  exec {pnm}<> <(:)
    74  coproc gs -q -sDEVICE=pnmraw -dSAFER -r$(( ores * scale )) -dBATCH \
    75         -sOutputFile=/dev/fd/$pnm "$1" -c quit
    76  page=1 gspid=$! loop=true

    79  while $loop && [ -d /proc/$gspid ] ;do 
    80      printf -v file page-%11d $((page++))
    81
    82      numcolor=$(
    83         ppmhist -noheader < <(
    84            pnmnoraw </dev/fd/${pnm} |
    85               tee >(
    86                  pnmscale $div |
    87                     tee >(pnmtojpeg -q $jpegqual >$file.jpg) >tmpfile)
    88         ) | wc -l
    89      )
    90      numcolor=$(( numcolor >= maxcol ? 255 : numcolor * shade ))
    91      
    92      read -u $COPROC -t 1 foo || loop=false # wait for showpage msg
    93      echo '' >&${COPROC[1]}                 # hit <return>
    94
    95      pnmquant <tmpfile $numcolor 2>/dev/null |
    96          pnmtopng >$file.png 2>/dev/null
    97      size=$(pnmfile <tmpfile)
   103...      
   104      { read pngsz;read jpgsz ;} < <(stat -c %s $file.{png,jpg})
   105      (( pngsz > jpgsz )) && rm $file.png tmpfile|| rm $file.jpg tmpfile
   111... done

Le script gère effectivement plusieurs fils d'entrée/sorties, simulténament
et interractivement.

Il s'agit donc d'une application multitâche, avec plein de forks, générés
au travers d'un processus (script) multithread qui gères les interactions.
(à la ligne 93, ghostscript commence à rasteriser la page suivante, tandis
 que le script fini la génération de l'image et la sélection de la plus
 légère.
 A la ligne 84, un nouveau process et généré pour chaque page générée par un
 seul process ghostscript qui traite le fichier en entier et un seul passage)

C'est de la sémantique.
Il me semble de la difference entre multitâche et multithread est: 
 La différence entre le fait de lancer plusieurs tâches en parallel 
 et le fait de converser avec plusieurs interlocuteurs simultanément.

-- 
 Félix Hauri  -  <felix at f-hauri.ch>  -  http://www.f-hauri.ch


More information about the gull mailing list