GNU Parallel esegue più comandi in parallelo: come funziona

Un software libero come GNU Parallel porta la parallelizzazione nelle mani di tutti gli utenti. Diventa possibile eseguire più comandi e script contemporaneamente sfruttando tutti i core del processore.

Oggi che si parla sempre più spesso di intelligenza artificiale, la parallelizzazione è divenuta un concetto essenziale nell’ambito del computingGNU Parallel è un’utilità basata su riga di comando che consente agli utenti Linux di eseguire più comandi in parallelo. Si tratta quindi di un potente strumento che dà modo di sfruttare al massimo la potenza di elaborazione multicore dei moderni processori.

Si dice spesso che tante applicazioni non sono capaci di sfruttare le configurazioni multicore. Questo avviene per diversi motivi: la programmazione parallela richiede una pianificazione e un design attenti per suddividere i compiti in modo efficace tra i vari core del processore. Inoltre, alcuni compiti possono avere dipendenze reciproche: ciò significa che un’attività deve essere completata per arrivare al risultato finale combinandosi con le altre parallelamente in esecuzione. In tali casi, la parallelizzazione potrebbe essere difficile da implementare senza introdurre complessi sistemi di sincronizzazione e gestione delle dipendenze.

Il vantaggio di GNU Parallel è che consegna i benefici della parallelizzazione nelle mani di utenti e sviluppatori rendendo possibile la gestione contemporanea di più comandi senza introdurre alcuna complicazione.

Cos’è GNU Parallel e come funziona

Il fiore all’occhiello di GNU Parallel è ovviamente l’esecuzione parallela: l’applicazione suddivide i comandi specificati in input in più processi separati che vengono eseguiti simultaneamente. Le differenze in fatto di prestazioni nel caso delle attività impegnative che, di norma, richiedono molto tempo per essere portate a conclusione sono davvero tangibili.

Il sistema su cui si basa GNU Parallel assicura un controllo flessibile sui processi in esecuzione, consentendo agli utenti di specificare il numero massimo di processi paralleli da avviare contemporaneamente. In questo modo è possibile scongiurare un eventuale sovraccarico del sistema in uso.

Semplice da usare, l’utilità consente di usare dei “segnaposto“, poi automaticamente sostituiti con gli argomenti appropriati in fase di esecuzione delle istruzioni fornite.

Il “GNU” deriva dal progetto omonimo la cui sigla sta per “GNU’s Not Unix“. Il progetto GNU è un’iniziativa che vuole puntare sul software libero e sulla sua adozione a ogni livello: GNU Parallel è uno dei numerosi strumenti e programmi sviluppati in seno all’iniziativa. GNU Parallel è un componente prezioso per chiunque lavori con sistemi Unix-like e voglia sfruttare al massimo le risorse di elaborazione disponibili.

Qualche esempio di utilizzo di GNU Parallel

Per usare GNU Parallel, il corrispondente pacchetto deve risultare installato sulla macchina Linux in uso. Per procedere in Ubuntu, per esempio, basta digitare sudo apt install parallel -y nella finestra del terminale.

Esecuzione di comandi da un file di input

Supponiamo di disporre di un file chiamato files.txt che contiene una lista di file. Si può pensare di utilizzare GNU Parallel per eseguire un comando su ciascun file in modo parallelo. L’istruzione seguente, da impartire sempre tramite la finestra del terminale Linux, esegue in parallelo il comando wc -l su ciascun file elencato in files.txt:

parallel -a files.txt wc -l

Il comando wc -lconta il numero di righe che compongono un file di testo e restituisce tale valore come output.

Anziché controllare uno dopo l’altro ciascun file e contare il numero di righe che ne compongono il contenuto, con GNU Parallel è possibile ottenere il responso in tempi rapidissimi proprio grazie alla parallelizzazione.

Nell’immagine, si vede che GNU Parallel ha esaminato ciascun file e riportato il numero di righe corrispondenti.

GNU Parallel esempio parallelizzazione

Esecuzione parallela di script bash

Se si ha uno script bash chiamato mioscript.sh che accetta un argomento in ingresso, è possibile ricorrere a GNU Parallel per eseguire i comandi contenuti nel file con argomenti diversi e in parallelo:

parallel ./mioscript.sh ::: arg1 arg2 arg3

L’esempio che presentiamo esegue in parallelo ./myscript.sh arg1, ./myscript.sh arg2 e ./myscript.sh arg3.

A questo proposito, Alex Plescan presenta un caso concreto ovvero la gestione di una serie di script bash il cui comportamento non è prevedibile a priori. Si pensi a script che possono richiedere più o meno tempo per essere eseguiti e che possono restituire degli errori. Il codice seguente, messo a punto da Plescan, genera automaticamente alcuni script .sh che “addormentano” il flusso di esecuzione per un periodo variabile tra 5 e 15 secondi per poi offrire 0 o 1 come exit code (rispettivamente successo o errore):

parallel "echo 'sleep \$((\$RANDOM%10+5)) && [ \$((\$RANDOM%2)) = 1 ] \
  && printf PASS \
  || (printf FAIL && exit 1)'" \
  '>' potentially_flaky_{1}.sh ::: {1..5}

Avviare più script contemporaneamente e memorizzare i dati sull’esecuzione di ciascun file .sh

Plescan invita a provare ad eseguire i comandi seguenti (basta incollarli nella finestra del terminale). Come si vede, l’esecuzione degli script non è più bloccata come quando viene eseguita con un approccio sequenziale ma il processore si avvantaggia elaborando più file .sh in contemporanea:

tests=(
  potentially_flaky_1.sh
  potentially_flaky_2.sh
  potentially_flaky_3.sh
  potentially_flaky_4.sh
  potentially_flaky_5.sh
)

parallel --progress --jobs 5 --delay 2 --timeout 3600 --shuf --results out.csv \
  bash {1} ::: ${tests[@]} ::: {1..10}

GNU Parallel bash

Il comando utilizza GNU Parallel per eseguire una serie di comandi bash specificati dal segnaposto {1} per diverse combinazioni di input. Ogni combinazione è data da un elemento dell’array ${tests[@]} combinato con un numero da 1 a 10. L’esecuzione avviene in parallelo fino a un massimo di 5 comandi contemporaneamente, con ritardi tra le esecuzioni, timeout di 1 ora e risultati salvati in un file dal nome out.csv:

  • --progress: Mostra un output interattivo in tempo reale che indica lo stato dell’esecuzione parallela dei comandi.
  • --jobs 5: Specifica che possono essere eseguiti fino a 5 comandi in parallelo contemporaneamente su altrettanti core della CPU.
  • --delay 2: Aggiunge un ritardo di 2 secondi tra l’avvio di ciascun comando.
  • --timeout 3600: Impone un timeout di 3600 secondi (1 ora) per ciascun comando. Se l’esecuzione dovesse superare questo limite di tempo, il comando viene arrestato.
  • --shuf: Mescola l’ordine delle combinazioni dei dati di input. In questo caso, le combinazioni sono mischiate in modo casuale.
  • --results out.csv: Salva i risultati delle esecuzioni dei comandi in un file chiamato out.csv.

Alla fine dell’elaborazione, il contenuto del file out.csv può essere esaminato con l’editor nano (nano out.csv) oppure aperto direttamente con un foglio elettronico.

Altri esempi di utilizzo di GNU Parallel

Per approfondire il funzionamento del programma e indagare sui possibili campi applicativi, è possibile consultare l’ebook su GNU Parallel a cura dello sviluppatore Ole Tange: la lettura del primo capitolo richiede poco tempo e consente di raccogliere tutte le informazioni che servono per usare GNU Parallel.

Un approccio simile ai precedenti può essere quello che coinvolge il download in parallelo di più file con il comando wget:

parallel wget ::: url1 url2 url3

È però possibile, per esempio, convertire immagini in altri formati usando la parallelizzazione:

parallel convert {} -resize 800x600 ::: image1.jpg image2.jpg image3.jpg

Oppure, ancora, creare delle miniature per ciascuna immagine di grandi dimensioni (nell’esempio i file derivati hanno prefisso min_):

parallel convert {} -resize 100x100 min_{} ::: *.jpg

Ma si possono anche eseguire query in parallelo sui database per verificarne il comportamento ed estrarre i dati che interessano:

parallel run_query {} ::: query1 query2 query3

Le potenzialità di GNU Parallel sono virtualmente sconfinate: qualunque comando conoscete e che utilizzate nella finestra del terminale Linux può essere automaticamente parallelizzato. A tal proposito, GNU Parallel è configurato dal suo autore Ole Tange per impegnare il massimo numero di core possibile. L’argomento --jobs visto in precedenza, consente di personalizzare tale comportamento e mettere eventualmente dei paletti.

Ti consigliamo anche

Link copiato negli appunti