Leer Multi-Threading Bash-scripts met GNU Parallel

Als je genoeg hebt van het feit dat je Bash-scripts eeuwen duren om uit te voeren, is deze tutorial iets voor jou. Vaak kun je Bash-scripts parallel uitvoeren, wat het resultaat aanzienlijk kan versnellen. Hoe? Gebruik de \texttt{GNU Parallel} utility, ook wel gewoon Parallel genoemd, met een aantal handige voorbeelden van GNU Parallel!

Parallel voert Bash-scripts parallel uit via een concept genaamd multi-threading. Met deze utility kun je verschillende taken per CPU uitvoeren in plaats van slechts één, waardoor de tijd om een script uit te voeren wordt verkort.

In deze tutorial ga je leren hoe je Bash-scripts met multi-threading kunt uitvoeren, met tal van geweldige voorbeelden van GNU Parallel!

Vereisten

Deze tutorial zit boordevol praktijkdemonstraties. Als je wilt volgen, zorg er dan voor dat je het volgende hebt:

  • A Linux computer. Any distribution will work. The tutorial uses Ubuntu 20.04 running on Windows Subsystem for Linux (WSL).
  • Ingelogd als een gebruiker met sudo-rechten.

GNU Parallel installeren

Om Bash-scripts met multithreading te versnellen, moet je eerst Parallel installeren. Laten we beginnen met downloaden en installeren.

1. Open een Bash-terminal.

2. Voer het commando \texttt{wget} uit om het Parallel-pakket te downloaden. Het onderstaande commando downloadt de nieuwste versie (\texttt{parallel-latest}) naar de huidige werkdirectory.

wget https://ftp.gnu.org/gnu/parallel/parallel-latest.tar.bz2

Als u liever een oudere versie van GNU Parallel wilt gebruiken, kunt u alle pakketten vinden op de officiële downloadsite.

3. Voer nu het tar-commando hieronder uit om het zojuist gedownloade pakket uit te pakken.

Hieronder gebruikt het commando de x-vlag om het archief uit te pakken, j om aan te geven dat het zich richt op een archief met een .bz2-extensie, en f om een bestand te accepteren als invoer voor het tar-commando. sudo tar -xjf parallel-latest.tar.bz2

sudo tar -xjf parallel-latest.tar.bz2

U moet nu een map hebben met de naam parallel- met de maand, dag en jaar van de laatste release.

4. Navigeer naar de map met het pakketarchief met cd. In deze handleiding wordt de map met het pakketarchief parallel-20210422 genoemd, zoals hieronder weergegeven.

Navigating to the Parallel archive folder

5. Installeer vervolgens build en install de GNU Parallel-binair door de volgende commando’s uit te voeren:

./configure
 make
 make install

Controleer nu of Parallel correct is geïnstalleerd door de versie te controleren die is geïnstalleerd.

parallel --version
Checking the GNU Parallel version

Wanneer u Parallel voor de eerste keer uitvoert, ziet u mogelijk ook een paar enge regels die tekst weergeven zoals perl: waarschuwing:. Die waarschuwingsberichten geven aan dat Parallel uw huidige taal- en landinstellingen niet kan detecteren. Maak je echter geen zorgen over die waarschuwingen voor nu. U leert later hoe u die waarschuwingen kunt oplossen.

Configuratie van GNU Parallel

Nu Parallel is geïnstalleerd, kunt u het meteen gebruiken! Maar eerst is het belangrijk om een paar kleine instellingen te configureren voordat u begint.

Terwijl u nog steeds in uw Bash-terminal bent, stemt u in met de GNU Parallel academisch onderzoekstoestemming door Parallel te vertellen dat u het zult citeren in elk academisch onderzoek door de parameter citation te specificeren gevolgd door will cite.

Als u GNU of de ontwikkelaars ervan niet wilt ondersteunen, is het niet vereist om GNU Parallel te citeren om het te gebruiken.

parallel --citation
will cite

Verander de taalinstelling door de volgende omgevingsvariabelen in te stellen door de onderstaande regels code uit te voeren. Het instellen van taal- en taalomgevingsvariabelen op deze manier is geen vereiste. Maar GNU Parallel controleert ze elke keer dat het wordt uitgevoerd.

Als de omgevingsvariabelen niet bestaan, zal Parallel er telkens over klagen zoals u hebt gezien in de vorige sectie.

Deze handleiding gaat ervan uit dat u een Engelssprekende bent. Andere talen worden ook ondersteund.

export LC_ALL=C man
export LANGUAGE=en_US
export LANG=en_US.UTF-8
Setting locale and language for GNU Parallel

Ad-hoc Shell-opdrachten uitvoeren

Laten we nu aan de slag gaan met het gebruik van GNU Parallel! Om te beginnen, leer je de basis syntax. Zodra je comfortabel bent met de syntax, ga je vervolgens over naar enkele handige voorbeelden van GNU Parallel.

Om te beginnen, laten we een super eenvoudig voorbeeld behandelen waarbij we alleen de getallen 1-5 echoën.

1. Voer in je Bash-terminal de volgende commando’s uit. Spannend, toch? Bash gebruikt het echo-commando om de getallen 1-5 naar de terminal te sturen. Als je elk van deze commando’s in een script zou plaatsen, zou Bash ze elk sequentieel uitvoeren, wachtend op het einde van de vorige.

In dit voorbeeld voer je vijf commando’s uit die bijna geen tijd in beslag nemen. Maar stel je voor dat die commando’s Bash-scripts waren die eigenlijk iets nuttigs deden maar heel lang duurden om uit te voeren?

 echo 1
 echo 2
 echo 3
 echo 4
 echo 5

Voer nu elk van die commando’s tegelijkertijd uit met Parallel zoals hieronder. In dit voorbeeld voert Parallel het echo-commando uit, aangeduid met de :::, geeft dat commando de argumenten 1, 2, 3, 4, 5. De drie dubbele punten vertellen Parallel dat je invoer via de opdrachtregel geeft in plaats van via de pijplijn (later meer hierover).

In het onderstaande voorbeeld heb je een enkel commando doorgegeven aan Parallel zonder opties. Hier startte Parallel, zoals bij alle Parallel-voorbeelden, een nieuw proces voor elk commando met een ander CPU-kern.

# Vanaf de opdrachtregel
 parallel echo ::: 1 2 3 4 5

Alle Parallel-opdrachten volgen de syntax parallel [Opties] <Commando om multi-threaden>.

3. Om te demonstreren hoe Parallel input ontvangt vanuit de Bash-pijplijn, maak een bestand genaamd count_file.txt zoals hieronder. Elk nummer vertegenwoordigt het argument dat je aan het echo-commando zult doorgeven.

 1
 2
 3
 4
 5

4. Voer nu het cat-commando uit om dat bestand te lezen en geef de output door aan Parallel, zoals hieronder wordt getoond. In dit voorbeeld vertegenwoordigt {} elk argument (1-5) dat aan Parallel zal worden doorgegeven.

# Vanuit de pijplijn cat count_file.txt | parallel echo {}
GNU Parallel Example #1

Vergelijking tussen Bash en GNU Parallel

Op dit moment lijkt het gebruik van Parallel misschien gewoon een ingewikkelde manier om Bash-commando’s uit te voeren. Maar het echte voordeel voor jou is tijdsbesparing. Onthoud, Bash zal op slechts één CPU-kern draaien, terwijl GNU Parallel op meerdere tegelijk zal draaien.

1. Om het verschil tussen opeenvolgende Bash-commando’s en Parallel te demonstreren, maak een Bash-script genaamd test.sh met de volgende code. Maak dit script in dezelfde map waar je eerder het count_file.txt hebt aangemaakt.

Het onderstaande Bash-script leest het bestand count_file.txt, slaapt gedurende 1, 2, 3, 4 en 5 seconden, geeft de lengte van de slaap weer op het terminal en eindigt.

#!/bin/bash
 nums=$(cat count_file.txt) # Lees count_file.txt
 for num in $nums           # Voor elke regel in het bestand, start een lus
 do
     sleep $num             # Lees de regel en wacht zoveel seconden als aangegeven
     echo $num              # Print de regel
 done

2. Voer nu het script uit met het time-commando om te meten hoe lang het duurt om het script te voltooien. Het duurt 15 seconden.

time ./test.sh

3. Gebruik nu opnieuw het time-commando om dezelfde taak uit te voeren, maar gebruik deze keer Parallel.

De onderstaande opdracht voert dezelfde taak uit, maar in plaats van te wachten tot de eerste lus is voltooid voordat de volgende begint, zal het er een op elk CPU-kern uitvoeren en er zoveel tegelijk starten als mogelijk is.

time cat count_file.txt | parallel "sleep {}; echo {}"
The prompt on the right side of the terminal confirms the time each command took to complete

Weet hoe de Droge Run werkt!

Het is nu tijd om wat meer real-world GNU Parallel-voorbeelden te bekijken. Maar voordat je dat doet, moet je eerst weten over de --dryrun-vlag. Deze vlag is handig als je wilt zien wat er zal gebeuren zonder dat Parallel het daadwerkelijk uitvoert.

De --dryrun vlag kan de laatste controle zijn voordat u een opdracht uitvoert die zich niet gedraagt zoals u dacht. Helaas, als u een opdracht invoert die uw systeem zou schaden, is het enige wat GNU Parallel u zal helpen doen het sneller schaden!

parallel --dryrun "rm rf {}"

GNU Parallel Voorbeeld #1: Bestanden downloaden van het web

Voor deze taak downloadt u een lijst met bestanden van verschillende URL’s op het web. Deze URL’s kunnen bijvoorbeeld webpagina’s voorstellen die u wilt opslaan, afbeeldingen, of zelfs een lijst met bestanden van een FTP-server.

Voor dit voorbeeld gaat u een lijst met archiefpakketten (en de SIG-bestanden) downloaden van de FTP-server van GNU parallel.

1. Maak een bestand genaamd download_items.txt, pak enkele downloadlinks van de officiële downloadsite en voeg ze toe aan het bestand gescheiden door een nieuwe regel.

 https://ftp.gnu.org/gnu/parallel/parallel-20120122.tar.bz2
 https://ftp.gnu.org/gnu/parallel/parallel-20120122.tar.bz2.sig
 https://ftp.gnu.org/gnu/parallel/parallel-20120222.tar.bz2
 https://ftp.gnu.org/gnu/parallel/parallel-20120222.tar.bz2.sig

U zou wat tijd kunnen besparen door de Beautiful Soup-bibliotheek van Python te gebruiken om alle links van de downloadpagina te schrapen.

2. Lees alle URL’s uit het download_items.txt-bestand en geef ze door aan Parallel, die wget zal aanroepen en elke URL zal doorgeven.

cat download_items.txt | parallel wget {}

Vergeet niet dat {} in een parallelle opdracht een aanduiding is voor de invoerreeks!

3. Misschien moet je het aantal threads controleren dat GNU Parallel tegelijkertijd gebruikt. Voeg indien nodig de parameter --jobs of -j toe aan het commando. De parameter --jobs beperkt het aantal threads dat tegelijkertijd kan worden uitgevoerd tot het door jou opgegeven aantal.

Bijvoorbeeld, om Parallel te beperken tot het tegelijkertijd downloaden van vijf URL’s, zou het commando er als volgt uitzien:

#!/bin/bash
 cat download_items.txt | parallel --jobs 5 wget {}

De --jobs parameter in het bovenstaande commando kan worden aangepast om elk gewenst aantal bestanden te downloaden, zolang de computer waarop je het uitvoert maar zoveel CPU’s heeft om ze te verwerken.

4. Om het effect van de --jobs parameter te demonstreren, pas je nu het aantal taken aan en voer je het time commando uit om te meten hoe lang elke uitvoering duurt.

 time cat download_items.txt | parallel --jobs 5 wget {}
 time cat download_items.txt | parallel --jobs 10 wget {}

GNU Parallel Voorbeeld #2: Uitpakken van archiefpakketten

Nu je al deze archiefbestanden hebt gedownload vanuit het vorige voorbeeld, moet je ze nu uitpakken.

Terwijl je in dezelfde map als de archiefpakketten bent, voer je het volgende Parallel commando uit. Let op het gebruik van het jokerteken (*). Aangezien deze map zowel archiefpakketten als de SIG-bestanden bevat, moet je Parallel vertellen om alleen .tar.bz2 bestanden te verwerken.

sudo parallel tar -xjf ::: *.tar.bz2

Bonus! Als je GNU parallel interactief gebruikt (niet in een script), voeg dan de --bar vlag toe om Parallel je een voortgangsbalk te laten tonen terwijl de taak wordt uitgevoerd.

Showing the output from the --bar flag

GNU Parallel Voorbeeld #3: Bestanden verwijderen

Als je de eerste twee voorbeelden hebt gevolgd, zou je nu veel mappen in je werkmap moeten hebben die ruimte in beslag nemen. Laten we dus al die bestanden parallel verwijderen!

Om alle mappen te verwijderen die beginnen met parallel- met behulp van Parallel, vermeld je alle mappen met ls -d en leid je elk van die map-paden door naar Parallel, waarbij je rm -rf oproept voor elke map, zoals hieronder weergegeven.

Vergeet de --dryrun-vlag niet!

ls -d parallel-*/ | parallel "rm -rf {}"

Conclusie

Nu kun je taken automatiseren met Bash en jezelf veel tijd besparen. Wat je ervoor kiest om met die tijd te doen, is aan jou. Of tijd besparen betekent dat je wat eerder stopt met werken of nog een andere ATA-blogpost leest, het is tijd terug in je dag.

Denk nu eens aan alle langlopende scripts in je omgeving. Welke kun je versnellen met Parallel?

Source:
https://adamtheautomator.com/how-to-speed-up-bash-scripts-with-multithreading-and-gnu-parallel/