Der Originalcode.

Der Originalcode.

Ich habe mir ein Skript ausgedacht, das einfach einen anderen Prozess im Hintergrund ausführt, der versucht, die maximale Anzahl laufender Prozesse (in diesem Fall 300) zu kontrollieren.

Es führt Skripte zunächst mit ca. 1-2 Millisekunden aus, verlangsamt sich aber nach mehreren Stunden Betrieb schließlich linear auf 200 ms - 350 ms Ausführungszeit. Ich verwende ein Array, um die PID-Nummer beizubehalten, lösche aber auch den Schlüssel, um die Tabellengröße zu verringern, aber ich habe das Gefühl, dass das der Übeltäter ist.

#!/bin/bash

threads=()
threadcounter=0

crd=0;

while true; 
do
        threadcounter=${#threads[@]}
        crdcounter=${#crds[@]}

        if [ "$threadcounter" -lt 300 ]
        then
                s1=$(($(date +%s%N)/1000000))
                pidf=$(/opt/remi/php/root/usr/bin/php cli.php initformula $crd >> /tmp/logger) &
                pidfid=$!
                s2=$(($(date +%s%N)/1000000))
                echo "Init " $crd $(expr $s2 - $s1 ) "ms"
                threads[$pidfid]+=$pidfid
        else
            for pid in "${!threads[@]}"; do 
                if [ ! -d "/proc/${pid}" ]
                then
                    unset threads[$pid]
                fi
            done;
        fi;

        if [ "$crd" -gt 9999999 ]
        then
            echo "completed all";
            exit;
        fi;

        crd=$(expr $crd + 1)
done;

Antwort1

Der Originalcode.

Zu Beginn starten Sie einfach 300 Kopien von cli.php. Dies erfordert etwa 1200 Prozesse, da Sie die zum Starten benötigte Zeit messen möchten.

Anschließend durchlaufen Sie die Variable in einer Schleife crdvon 300 bis 9999999.

  • Wenn die Shell der Meinung ist, dass im threadsArray freie Steckplätze vorhanden sind, startet sie cli.phpmithilfe der vier Prozesse einen neuen.

  • Andernfalls durchlaufen Sie ungefähr 300 Prozesse, um den
    Kernel dazu zu bringen, das /procvirtuelle Dateisystem zu füllen und zu prüfen, ob ein
    Verzeichnis vorhanden ist. Fehlende Verzeichnisse führen dazu, dass Einträge
    aus dem threadsArray gelöscht werden.

Sie haben ein ungenutztes Array namens crds.

Denn nach den ersten 300 erstellt jede Schleife der CRD-Variable eine neue Kopie, cli.phpwenn in der Prozesstabelle freie Slots vorhanden sind, kann aber bis zu 300 entfernen, wenn die Tabelle voll ist. Am Ende des Laufs wussten wir nur, dass zwischen 300 und ungefähr 9.967.000 cli.phpProzesse gestartet wurden, wobei die Zahl von der Geschwindigkeit Ihrer Maschine, der Ausführungsdauer cli.phpund der Maschinenlast abhängt. 6 Größenordnungen sind eine Menge, die optimiert werden muss!

Als Faustregel gilt, dass auf einer modernen Maschine das Starten eines Prozesses auf einem Kern 1 ms dauert. Ihre anfängliche Startrate ist also nicht schlecht. Ich würde einen deutlichen Rückgang der Startrate erwarten, wenn Sie keine freien Kerne mehr haben, um neue Prozesse zu starten.

Verbesserungen

Eine Möglichkeit, dies zu beschleunigen, wäre, anstelle ! kill -0 $pidvon zu verwenden . Dies beendet nichts, gibt aber eine Fehlermeldung zurück, wenn der Prozess nicht existiert. ist eine Shell-integrierte Funktion (wie ), aber der Arbeitsaufwand für den Kernel ist geringer. Dies ist am effektivsten, wenn die meiste Zeit keine freien Slots im Array vorhanden sind.[ ! -d "/proc/${pid}" ]kill -0kill[threads

Eine zweite Verbesserung wäre, den Aufruf des externen Programms exprdurch die Verwendung der integrierten $(( ... ))Arithmetik zu ersetzen und so den Aufwand für das Starten einer Kopie von zu reduzieren cli.php. Dies ist am effektivsten, wenn im labelsArray die meiste Zeit freie Slots vorhanden sind.

Um weitere Analysen durchführen zu können, müssen wir die ungefähre Laufzeit cli.phpund die Anzahl der Durchläufe kennen.

Wie im BUGSAbschnitt im Bash-Handbuch beschrieben It's too big and too slow., besteht durchaus Raum für Verbesserungen bei der Array-Implementierung in Bash.

Alternative Implementierungen

machen

In den Kommentaren wird empfohlen, xargsoder zu verwenden parallel. Ich bevorzuge häufig die Verwendung von . makeAls erstes muss bestimmt werden, wie viele Kopien von cli.phpgewünscht werden. Dann ein einfaches Makefilewie

%:
\t/opt/remi/php/root/usr/bin/php cli.php initformula $@

wobei \t ein Tabulatorzeichen ist. (Diese einfache Version geht davon aus, dass Sie keine Dateien mit numerischen Namen im Bereich von 0 bis 9999999 haben.) Rufen Sie dann make as auf.

make -O -j 300 $(seq 0 9999999) > /tmp/logger

wenn Sie die vollen 10.000.000 cli.php-Aufrufe möchten. Gründe, warum ich es vorziehe, makeeinzuschließen xargs, dass keine übermäßigen Schritte erforderlich sind, um die Verarbeitung abzubrechen, wenn cli.php Fehler zurückgibt.

xargs

Für eine xargsLösung versuchen Sie

seq 0 9999999 | xargs -n 1 -P 300 /opt/remi/php/root/usr/bin/php cli.php initformula > /tmp/logger

was einfacher ist.

Schlag

Eine Bash-Lösung, die wait -nfdie PIDs verwendet und sich nicht darum kümmert, sie zu verfolgen, könnte jedoch eher dem Geschmack des OP entsprechen. Sie startet die ersten 300 Prozesse und startet dann, wenn sie erkennt, dass einer von ihnen beendet ist, einen weiteren. Sobald der 10.000.000. gestartet wurde, wartet sie ein letztes Mal, bis alle Jobs beendet sind. Nicht genau der gleiche Algorithmus, aber sehr nah dran.

#!/bin/bash
for(crd=0;crd<300;crd++); do
    /opt/remi/php/root/usr/bin/php cli.php initformula $crd & 
done > /tmp/logger
for(;crd<=9999999;crd++); do
    wait -fn
    /opt/remi/php/root/usr/bin/php cli.php initformula $crd &
done >> /tmp/logger
wait

verwandte Informationen