Come utilizzare l'elaborazione multi-thread negli script Bash

0
150
Aleksey Mnogosmyslov/Shutterstock.com< /figure>

La programmazione multi-thread è sempre stata di interesse per gli sviluppatori per aumentare le prestazioni delle applicazioni e ottimizzare l'utilizzo delle risorse. Questa guida ti introdurrà alle basi della codifica multi-thread di Bash.

Che cos'è la programmazione multi-thread?

Un'immagine vale più di mille parole e questo vale quando si tratta di mostrare la differenza tra la programmazione a thread singolo (1) e la programmazione multi-thread (>1) in Bash:

sleep 1 sleep 1 &amp ; dormi 1

La nostra prima configurazione di programmazione multi-thread o mini script one-liner non avrebbe potuto essere più semplice; nella prima riga, dormiamo per un secondo usando il comando sleep 1. Per quanto riguarda l'utente, un singolo thread stava eseguendo una singola sospensione di un secondo.

Nella seconda riga, abbiamo due comandi di sospensione da un secondo. Ci uniamo a loro usando un & separator, che non agisce solo come separatore tra i due comandi di sospensione, ma anche come indicatore per Bash di avviare il primo comando in un thread in background.

Normalmente, si termina un comando utilizzando un punto e virgola (;). In questo modo si eseguirà il comando e solo allora si procederà al comando successivo elencato dietro il punto e virgola. Ad esempio, eseguendo il sonno 1; il sonno 1 richiederebbe poco più di due secondi – esattamente un secondo per il primo comando, un secondo per il secondo e una piccola quantità di sovraccarico del sistema per ciascuno dei due comandi.

Tuttavia, invece di terminare un comando con un punto e virgola, si possono usare altri terminatori di comando che Bash riconosce come &, && e ||. Il && la sintassi è del tutto estranea alla programmazione multi-thread, semplicemente fa questo; procedere con l'esecuzione del secondo comando solo se il primo è andato a buon fine. Il || è l'opposto di && ed eseguirà il secondo comando solo se il primo non è riuscito.

Tornando alla programmazione multi-thread, utilizzando & poiché il nostro terminatore di comando avvierà un processo in background eseguendo il comando che lo precede. Quindi procede immediatamente con l'esecuzione del comando successivo nella shell corrente lasciando che il processo in background (thread) venga eseguito da solo.

Annuncio

Nell'output del comando possiamo vedere l'avvio di un processo in background (come indicato da [1] 445317 dove 445317 è l'ID del processo o il PID del processo in background appena avviato e [1] indica che questo è il nostro primo processo in background ) e successivamente viene terminato (come indicato da [1]+ Done sleep 1).

Se desideri visualizzare un ulteriore esempio di gestione dei processi in background, consulta la nostra Bash Automation and Scripting Basics (Parte 3) articolo. Inoltre, potrebbero essere interessanti gli hack di terminazione dei processi di Bash.

Dimostriamo ora che stiamo effettivamente eseguendo due processi di sospensione contemporaneamente:

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

Qui avviamo il nostro processo di sospensione a tempo e possiamo vedere come il nostro comando a thread singolo è stato eseguito per esattamente 1.003 secondi prima che venisse restituito il prompt della riga di comando.

Tuttavia, nel secondo esempio, ci è voluto circa lo stesso tempo (1.005 secondi) anche se stavamo eseguendo due periodi (e processi) di sospensione, anche se non consecutivi. Anche in questo caso abbiamo utilizzato un processo in background per il primo comando di sospensione, che porta all'esecuzione (semi)parallela, ovvero multi-thread.

Pubblicità

Abbiamo anche usato un wrapper subshell ($(…)) attorno ai nostri due comandi di sospensione per combinarli insieme nel tempo. Come possiamo vedere, il nostro output fatto viene mostrato in 1.005 secondi e quindi i due comandi sleep 1 devono essere stati eseguiti contemporaneamente. Interessante è il piccolissimo aumento del tempo di elaborazione complessivo (0,002 secondi) che può essere facilmente spiegato dal tempo necessario per avviare una subshell e dal tempo necessario per avviare un processo in background.

Gestione dei processi multi-thread (e in background)

In Bash, la codifica multi-thread normalmente coinvolge i thread in background da uno script principale di una riga o uno script Bash completo. In sostanza, si può pensare alla codifica multi-thread in Bash come all'avvio di diversi thread in background. Quando si inizia a codificare utilizzando più thread, diventa subito chiaro che tali thread di solito richiedono un po' di gestione. Ad esempio, prendi l'esempio fittizio in cui avviamo cinque periodi (e processi) simultanei di sospensione in uno script Bash;

#!/bin/bash dormi 10 & dormire 600 & dormire 1200 & dormire 1800 & dormire 3600 &

Quando avviamo lo script (dopo averlo reso eseguibile con chmod +x rest .sh), non vediamo alcun output! Anche se eseguiamo lavori (il comando che mostra tutti i lavori in background in corso), non c'è output. Perché?

Il motivo è che la shell che è stata utilizzata per avviare questo script (cioè la shell corrente) non è la stessa shell (né lo stesso thread; per iniziare a pensare in termini di subshell come thread in sé e per sé) che ha eseguito il sonno effettivo comandi o li ha messi in background. Era piuttosto la (sub)shell che è stata avviata quando ./rest.sh è stato eseguito.

Cambiamo il nostro script aggiungendo lavori all'interno dello script. Ciò garantirà che i lavori vengano eseguiti dall'interno della (sotto)shell dove è rilevante, lo stesso da dove sono stati avviati i periodi (e i processi) di sospensione.

Questa volta possiamo vedere l'elenco dei processi in background avviati grazie al comando jobs in la fine della sceneggiatura. Possiamo anche vedere i loro PID (identificatori di processo). Questi PID sono molto importanti quando si tratta di gestire e gestire processi in background.

Pubblicità

Un altro modo per ottenere l'identificatore di processo in background è interrogarlo immediatamente dopo aver posizionato un programma/processo in background:

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

Simile al nostro comando jobs (con i nuovi PID ora quando abbiamo riavviato il nostro script rest.sh), grazie all'eco della variabile Bash ${!}, ora vedremo i cinque PID visualizzati quasi subito dopo l'avvio dello script: i vari processi di sospensione sono stati inseriti in thread in background uno dopo l'altro.

Il comando wait

Una volta avviato il nostro background processi, non abbiamo altro da fare che aspettare che siano finiti. Tuttavia, quando ogni processo in background sta eseguendo un'attività secondaria complessa e abbiamo bisogno dello script principale (che ha avviato i processi in background) per riprendere l'esecuzione quando uno o più processi in background terminano, abbiamo bisogno di codice aggiuntivo per gestirlo.

Espandiamo ora il nostro script con il comando wait per gestire i nostri thread in background:

#!/bin/bash sleep 10 & T1=${!} dorme 600 & T2=${!} dormi 1200 & T3=${!} dorme 1800 & T4=${!} dorme 3600 & T5=${!} echo “Questo script ha avviato 5 thread in background attualmente in esecuzione con i PID ${T1}, ${T2}, ${T3}, ${T4}, ${T5}.” wait ${T1} echo “Il thread 1 (sleep 10) con PID ${T1} è terminato!” wait ${T2} echo “Il thread 2 (sleep 600) con PID ${T2} è terminato!”

Qui abbiamo ampliato il nostro script con due comandi wait che aspettano il PID allegato al primo e il secondo thread da terminare. Dopo 10 secondi, esiste il nostro primo thread e ci viene notificato lo stesso. Passo dopo passo, questo script farà quanto segue: avvierà cinque thread quasi contemporaneamente (sebbene l'avvio dei thread stessi sia ancora sequenziale e non parallelo) in cui ciascuno dei cinque sleep verrà eseguito in parallelo.< /p>

Lo script principale quindi (in sequenza) segnala il thread creato e successivamente attende che l'ID processo del primo thread venga terminato. Quando ciò accade, segnalerà in sequenza sulla fine del primo thread e inizierà un'attesa per la fine del secondo thread, ecc.

Pubblicità

Uso degli idiomi Bash &, ${!} e il Il comando wait ci offre una grande flessibilità quando si tratta di eseguire più thread in parallelo (come thread in background) in Bash.

Conclusione

In questo articolo abbiamo esplorato le basi dello scripting multi-thread di Bash. Abbiamo introdotto l'operatore del processo in background (&) utilizzando alcuni esempi facili da seguire che mostrano comandi di sospensione sia a thread singolo che multi-thread. Successivamente, abbiamo esaminato come gestire i processi in background tramite gli idiomi Bash comunemente usati ${!} e attendere. Abbiamo anche esplorato il comando jobs per vedere l'esecuzione di thread/processi in background.

Se ti è piaciuto leggere questo articolo, dai un'occhiata al nostro articolo Bash Process Termination Hacks.