2017-01-03 4 views
1

Ein Ziel in meinem Makefile ist eine sehr CPU- und zeitraubende Aufgabe. Aber ich kann die Arbeitslast aufteilen und die Aufgabe mehrmals parallel ausführen, um den gesamten Prozess zu beschleunigen.make: Mehrere Tasks parallel ausführen und auf die Fertigstellung warten

Mein Problem ist, dass make nicht auf den Abschluss aller Prozesse wartet.

Betrachten Sie dieses einfache Skript, mit dem Namen myTask.sh:

#!/bin/bash 

echo "Sleeping $1 seconds" 
sleep $1 
echo "$1 are over!" 

Jetzt wollen wir nennen dies von einem Bash-Skript, und verwenden Sie wait für alle Aufgaben warten vervollständigen:

#!/bin/bash 

echo "START" 
./myTask.sh 5 & 
./myTask.sh 15 & 
./myTask.sh 10 & 

wait # Wait for all tasks to complete 

echo "DONE" 

Der Ausgang ist wie erwartet:

START 
Sleeping 15 seconds 
Sleeping 5 seconds 
Sleeping 10 seconds 
5 are over! 
10 are over! 
15 are over! 
DONE 

Aber wenn man versucht, das gleiche in ein Makefile:

test: 
    echo "START" 
    ./myTask.sh 5 & 
    ./myTask.sh 15 & 
    ./myTask.sh 10 & 
    wait 
    echo "DONE" 

es nicht funktioniert:

START 
Sleeping 5 seconds 
Sleeping 15 seconds 
Sleeping 10 seconds 
DONE 
[email protected]:~/testwait $5 are over! 
10 are over! 
15 are over! 

Natürlich habe ich mehrere Ziele schaffen könnte, die „gebaut“ werden können parallel nach Marke, oder lassen Sie die Bash-Skript laufen lassen nur welche die Aufgaben ausführt. Aber gibt es einen Weg, es mehr zu tun, als was ich schon versuchte?

+0

Mein erster Versuch wäre, alle relevanten Befehle in die gleiche Zeile zu setzen: './myTask.sh 5 & ./myTask.sh 15 & ./myTask.sh 10 & wait' – melpomene

+1

Idealer Job für ** GNU Parallel ** ... 'parallel ./myTask.sh ::: 5 10 15' –

+0

Wenn Sie ** GNU make ** verwenden, und die "ONESHELL" -Feature installiert ist, wird Ihr Skript funktionieren * "wie es ist" * wenn Sie eine Zeile mit '.ONESHELL:' am Anfang hinzufügen, da dies Ihre gesamte erzwingen wird Rezept, um in einem einzigen Aufruf Ihrer Shell zu laufen. –

Antwort

4

Jede einzelne logische Zeile in einem Rezept wird in einer eigenen Shell aufgerufen. Also Ihr Make-Datei ausgeführt wird, im Grunde diese:

test: 
     /bin/sh -c 'echo "START"' 
     /bin/sh -c './myTask.sh 5 &' 
     /bin/sh -c './myTask.sh 15 &' 
     /bin/sh -c './myTask.sh 10 &' 
     /bin/sh -c 'wait' 
     /bin/sh -c 'echo "DONE"' 

Sie sollten es alle laufen in einer einzigen Schale machen Semikolons und Backslash/Zeilenumbrüche mit den physikalischen Leitungen in eine logische Linie zu kombinieren:

test: 
     echo "START"; \ 
     ./myTask.sh 5 & \ 
     ./myTask.sh 15 & \ 
     ./myTask.sh 10 & \ 
     wait; \ 
     echo "DONE" 
+0

'&' ist bereits ein Befehlstrennzeichen. Sie brauchen kein extra ';'. – melpomene

+0

Guter Punkt. Aktualisiert. Danke. – MadScientist

+0

_Jede einzelne logische Zeile in einem Rezept wird in einer eigenen Shell aufgerufen._ Das war der fehlende Punkt. Vielen Dank! – sweber

3

Warum nicht Verwenden Sie die bereits in make eingebauten Mechanismen? Etwas wie folgt aus:

task%: 
     sh task.sh $* 

test: task5 task15 task10 
     echo "DONE" 

Sie können den Grad der Parallelität auf der Make-Befehlszeile anzupassen, anstatt es hart codiert in Ihr Make-Datei mit (zB Verwendung ‚-j 2-Test machen‘, wenn Sie 2 Kerne verfügbar und 'make -j 32 test' wenn du 32 Kerne hast)

+0

Wie senden Sie bitte Parameter? Z.B. "Aufgabe 5" anstatt "Aufgabe 5". –

+0

@MarkSetchell was meinst du? task5 ist der Name eines Ziels, es muss die syntaktischen Anforderungen für ein Ziel erfüllen. Im Rezept für das 'task5'-Ziel ist der Stamm $ * 5 und Sie können damit alles machen, was Sie wollen (zB verwenden Sie es als Parameter für das' task.sh'-Skript, wie im obigen Beispiel gezeigt). –

+0

Entschuldigung , Du hast recht. Ich vermasselte –

Verwandte Themen