Prozessverwaltung
Andreas Korthaus
- php
Hallo!
Wollte mich dann auch mal mit der Prozessverwaltung in PHP mittels http://www.php3.de/manual/de/ref.pcntl.phpversuchen. Kennt vielleicht jemand eine gute und vor allem _einfach_zu_verstehende_ Quelle um mal ein paar Grundlagen zur Thread-/Prozessverwaltung von Linux zu lernen?
Ich verstehe nämlich leider nichtmal die kurze Erklärung im PHP-Manual komplett:
On success, the PID of the child process is returned in the parent's thread of execution, and a 0 is returned in the child's thread of execution. On failure, a -1 will be returned in the parent's context, no child process will be created, and a PHP error is raised.
OK: Bei Erfolg wird dem Eltern/Vater-Thread die Prozess-ID des Kinder-Prozesses zurückgegeben, eine "0" wird dem Kinder-Thread zurückgegeben, und ein "-1" bei Fehler. Dazu steht da folgendes Beispiel:
Beispiel 1. pcntl_fork() Example
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {
// we are the parent
} else {
// we are the child
}
?>
Was ich daran nicht verstehe, das eine Script hat erstmal nur einen Thread und einen Prozess. Dann wird durch fork ein Kinderprozess gestartet. Was ich nicht verstehe - wenn man mal den Fehler (-1) außen vorläßt - steht da eine Weiche, entweder $PID ist 0 oder hat eine Nummer > 0. Aber beides ist wahr, es gibt ja jetzt 2 Threads bzw. Prozesse, laufen dann beide Prozesse durch diese Weiche, der eine in die eine Richtung, der andere in die andere Richtung? Laufen dann also 2 Prozesse in ein und demselben Script? Da steht immer "gibt XY dem einen oder dem anderen Thread zurück", aber das Script gehört doch ausschließlich dem Vater-Thread, oder? Und anhand der PID kann man im Script drauf reagieren? Einmal geht das innderhalb der Weiche, klar, aber wenn ich danach auf einen speziellen Prozess zugreifen will, kann ich ja nicht mehr PID=0 verwenden, denn das gilt ja für alle Kinderprozesse, oder? Könnte man so auch später im Script alle Kinderprozesse gleichzeitig ansprechen? Über die PID kann man die Kinderprozesse ja nachdem ob die IF-Weiche zu Ende ist ja nur noch beenden, oder? Oder könnte ich auch später im Script einen speziellen Kinderprozess dazu veranlassen einen bestimmten PHP-Code auszuführen?
Und was ist der Unterschied zwischen einem Prozess und einem Thread? Prozess ist doch das was mir z.B. der Windows Task-Manager anzeigt, oder? Aber was ist jetzt ein Thread?
Ich versuche gerade nämlich mal ein Testscript zu schreiben, welches so viele Socketverbindungen wie möglich zu demselben externen Server herstellt(HTTP-GET Request). Vorab, was ist hier eigentlich der Vorteil vieler Prozesse, im Gegensatz zu einer Schleife in einem Prozess? PHP kann doch sowieso nur eine begrenzte Anzahl von Befehlern bearbeiten und wird die Prozesse doch auch in einer Warteschlange-schieben und nacheinander abarbeiten, oder? Oder muß man hierbei nicht jedesmal auf den Response des HTTP-Request warten?
Jedenfalls habe ich mir das so vorgestellt:
for($i=1;$i<10;$i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if (!$pid) {
for($j=1;$j<100;$j++) {
fsockopen(...);
fputs(...);
}
}
}
Würde das schon reichen, oder ist das Quatsch? Wieviele Prozesse verwendet man für so etwas erfahrungsgemäß?
Hat jemand schonmal pcntl-Funktionen bei PHP eingesetzt? Dazu muß ich doch PHP selbst kompilieren, mit --enable-pcntl wenn ich das richtig verstanden habe, oder?
Viele Grüße
Andreas
Hallo Andreas,
Kennt vielleicht jemand eine gute und vor allem
_einfach_zu_verstehende_ Quelle um mal ein paar
Grundlagen zur Thread-/Prozessverwaltung von
Linux zu lernen?
Unix-Linux-Systemprogrammierung (Herold, ADW-Verlag)
Advanced Programming In The Unix(TM) Environment (Stevens, ADW-Verlag, Professional Computing Series)
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if ($pid) {
// we are the parent
} else {
// we are the child
}?>
Was ich daran nicht verstehe, das eine Script
hat erstmal nur einen Thread und einen Prozess.
Jups.
Dann wird durch fork ein Kinderprozess
gestartet.
Jups.
Was ich nicht verstehe - wenn man mal den
Fehler (-1) außen vorläßt - steht da eine
Weiche, entweder $PID ist 0 oder hat eine
Nummer > 0.
Jups.
Aber beides ist wahr,
Nein. Im einen Prozess ist das eine wahr, im
anderen das andere.
es gibt ja jetzt 2 Threads bzw. Prozesse,
Zwei Prozesse. Ein sehr, sehr wichtiger
Unterschied.
laufen dann beide Prozesse durch diese Weiche,
Ja.
der eine in die eine Richtung, der andere in
die andere Richtung?
Ja.
Laufen dann also 2 Prozesse in ein und
demselben Script?
fork() erstellt eine komplette Kopie des laufenden
Prozesses.
Da steht immer "gibt XY dem einen oder dem
anderen Thread zurück",
Hae?
Man, verwechsele nicht Thread und Prozess. Das
ist ein himmelweiter(!) Unterschied.
aber das Script gehört doch ausschließlich dem
Vater-Thread, oder?
Hae?
fork() macht folgendes: es erstellt eine
*komplette* Kopie des aktuellen Prozesses.
Einziger Unterschied: der PID-Variablen wird in
der einen Kopie die PID des neuen Prozesses
zugewiesen, der PID-Variablen in der anderen Kopie
0. Danach wird ganz normal weitergemacht, als
sei nichts geschehen.
Und anhand der PID kann man im Script drauf
reagieren?
Korrekt.
Einmal geht das innderhalb der Weiche, klar,
aber wenn ich danach auf einen speziellen
Prozess zugreifen will, kann ich ja nicht mehr
PID=0 verwenden, denn das gilt ja für alle
Kinderprozesse, oder?
Im *Kindprozess* ist die PID 0. Dort kann man sie
mit getpid(2) herausfinden. Im Vaterprozess ist
sie eine (mehr oder weniger) zufaellige
Integer-Zahl.
Könnte man so auch später im Script alle
Kinderprozesse gleichzeitig ansprechen?
Nein, nur nacheinander.
Über die PID kann man die Kinderprozesse ja
nachdem ob die IF-Weiche zu Ende ist ja nur
noch beenden, oder?
Du kannst ueber kill(2) beliebige Signale (siehe
signal(3)) schicken.
Oder könnte ich auch später im Script einen
speziellen Kinderprozess dazu veranlassen
einen bestimmten PHP-Code auszuführen?
Wenn du mit Pipes arbeitest oder mit Signalen,
klar, warum nicht?
Und was ist der Unterschied zwischen einem
Prozess und einem Thread?
Ein Prozess hat einen komplett eigenen Adressraum,
also eigene Variablen, eigenen Speicher, etc.
Ein Thread ist nur ein etwas im selben Programm,
hat denselben Adressraum. Einfachste Auswirkung:
ein Thread hat z. B. keine PID. Es ist kein
eigener Prozess. Deshalb verbraucht er auch viel
weniger Ressourcen.
Ja, ich weiss, unter Linux sieht man (noch)
Threads in den Prozess-Listen. Das liegt daran,
dass Threads unter Linux keine Kernelthreads sind,
sondern abgespeckte (lightweight) Prozesse, die
ueber das memory filesystem miteinander
kommunizieren. Ist natuerlich sehr langsam, das
ganze.
Vorab, was ist hier eigentlich der Vorteil
vieler Prozesse, im Gegensatz zu einer
Schleife in einem Prozess?
Ehm, denk doch mal nach :) Ein einziger Prozess
ist synchron. Mehrere Prozesse sind asynchron.
Ein einziger Prozess kann nur einen Request nach
dem anderen machen. Mehrere Prozesse koennen
jeweils einen Request (fast) simultan mit den
anderen machen.
PHP kann doch sowieso nur eine begrenzte Anzahl
von Befehlern bearbeiten und wird die Prozesse
doch auch in einer Warteschlange-schieben und
nacheinander abarbeiten, oder?
Was hat das mit PHP zu tun?
Oder muß man hierbei nicht jedesmal auf den
Response des HTTP-Request warten?
Hae?
for($i=1;$i<10;$i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if (!$pid) {
for($j=1;$j<100;$j++) {
fsockopen(...);
fputs(...);
}
}
}Würde das schon reichen, oder ist das Quatsch?
Prinzipiell reicht das.
Wieviele Prozesse verwendet man für so etwas
erfahrungsgemäß?
Was hast du vor?
Gruesse,
CK
Hi Christian!
Unix-Linux-Systemprogrammierung (Herold, ADW-Verlag)
Advanced Programming In The Unix(TM) Environment (Stevens, ADW-Verlag, Professional Computing Series)
Gibts da nichts online? Ist das Thema denn soooo komplex?
Ein Prozess hat einen komplett eigenen Adressraum,
also eigene Variablen, eigenen Speicher, etc.
Ein Thread ist nur ein etwas im selben Programm,
hat denselben Adressraum. Einfachste Auswirkung:
ein Thread hat z. B. keine PID. Es ist kein
eigener Prozess. Deshalb verbraucht er auch viel
weniger Ressourcen.
Also kann man dann auch innerhalb eines Prozesses mehrere Threads starten? Bezogen auf mein Beispiel unten, könnte ich anstatt neue Prozesse zu starten genauso neue Threads innerhalb des einen Prozesses starten, mit selbigem Ergebnis, also dass die HTTP-Requests parallel versendet werden, bei niedrigerer Hardware-Auslastung? Geht das überhaupt bzw. geht das mit PHP?
Ja, ich weiss, unter Linux sieht man (noch)
Threads in den Prozess-Listen. Das liegt daran,
dass Threads unter Linux keine Kernelthreads sind,
sondern abgespeckte (lightweight) Prozesse, die
ueber das memory filesystem miteinander
kommunizieren. Ist natuerlich sehr langsam, das
ganze.
Heißt das man sollte das bei Linux doch lieber lassen?
Ehm, denk doch mal nach :) Ein einziger Prozess
ist synchron. Mehrere Prozesse sind asynchron.
Ja, aber das ändert ja erstmal nicht daran das die CPU damit auch nicht schneller wird. Wird da also irgendwo was gespart.
Ein einziger Prozess kann nur einen Request nach
dem anderen machen. Mehrere Prozesse koennen
jeweils einen Request (fast) simultan mit den
anderen machen.
Was meinst Du hier mit Request? Einen HTTP-Request wie unten beschreiben?
PHP kann doch sowieso nur eine begrenzte Anzahl
von Befehlern bearbeiten und wird die Prozesse
doch auch in einer Warteschlange-schieben und
nacheinander abarbeiten, oder?Was hat das mit PHP zu tun?
Ich kenne mich da jetzt wirklich nicht aus, nur, wenn ich jetzt PHP verwende, also ich erstelle 10 Kinderprozesse, greifen diese Prozesse dann alle über die gegebenen Schnittstellen direkt auf OS-Funkionene zu, z.B. um einen HTTP-Request abzusenden? ich hatte jetzt gedacht das da der PHP Interpreter oder sowas noc dazwischen hängt, aber das Script ist ja, wenn es bereits ausgeführt wird schon interpretiert, oder?
Oder muß man hierbei nicht jedesmal auf den
Response des HTTP-Request warten?Hae?
Wenn ich in einem Script in einer schleife fsockopen, fputs("GET..."), fclose verwende, läuft die Schleife erst weiter, wenn die Antwort vom Server gekommen ist, wenn ich das auf mehrere Prozesse verteile, können alle (fast) gleichzeitig anfangen, ohne auf andere Prozesse Rücksicht nehmen zu müssen.
for($i=1;$i<10;$i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die("could not fork");
} else if (!$pid) {
for($j=1;$j<100;$j++) {
fsockopen(...);
fputs(...);
}
}
}
Was hast du vor?
Ich würde gerne mal ein paar möglichst realistische Performance-Vergleiche machen. Hierzu habe ich einige Server in verschiedenen voneinander getrennten Netzen, von denen aus ich je ein Script starten möchte, welches möglichst viele HTTP-Requests an den zu testenden Server sendet. Mit der Schleife alleine, ohne fork, komme ich nicht sehr weit, daher hoffe ich das ich das ganze mit fork beschleunigen kann. Ich weiß noch nicht wo jetzt genau die Engpässe liegen, ich vermute aber das durch das Warten auf die Antwort des HTTP-Requests die meiste Zeit verschwendet wird.
Viele Grüße
Andreas
Hallo Andreas,
Unix-Linux-Systemprogrammierung (Herold, ADW-Verlag) Advanced Programming In The Unix(TM) Environment (Stevens, ADW-Verlag, Professional Computing Series) Gibts da nichts online? Ist das Thema denn soooo komplex?
Ersteres habe ich auch, das hat 1147 Seiten. ;-)
Also kann man dann auch innerhalb eines Prozesses mehrere Threads starten?
Ja. Du musst aber im Prozess einen eigenen Scheduler haben. Bei normalen Prozessen sieht das so aus:
+--------------------------------------------------------------------------+ | Kern | | +--------------------------------------------------------+ | | | Scheduler | | | +--------------------------------------------------------+ | | ^ ^ ^ | | | | | | +--------------------------------------------------------------------------+ | | | v v v +-------------+ +-------------+ +-------------+ | Prozess | | Prozess | | Prozess | +-------------+ +-------------+ +-------------+
Wenn Du Threas innerhalb eines Pozesses haben willst, dann brauchst Du innerhalb des Prozesses einen eigenen Scheduler:
+--------------------------------------------------------------------------+ | Kern | | +--------------------------------------------------------+ | | | Scheduler | | | +--------------------------------------------------------+ | | ^ ^ ^ | | | | | | +--------------------------------------------------------------------------+ | | | v v | +-------------+ +-------------+ +--------------------------------------+ | Prozess | | Prozess | | | Prozess | +-------------+ +-------------+ | v | | +--------------+ +---------+ | | | Scheduler | <--> | Thread | | | +--------------+ +---------+ | | ^ ^ | | | `---- | | v \ | | +-----------+ | | | | Thread | v | | +-----------+ +------------+ | | | Thread | | | +------------+ | | | +--------------------------------------+
In der IX 12/2002 auf Seite 110 wird eine neue Thread-Biblithek für Linux vorgestellt, die das o.g. kann. Diese ist aber noch "experimentell".
Bezogen auf mein Beispiel unten, könnte ich anstatt neue Prozesse zu starten genauso neue Threads innerhalb des einen Prozesses starten, mit selbigem Ergebnis, also dass die HTTP-Requests parallel versendet werden, bei niedrigerer Hardware-Auslastung?
Theoretisch: ja.
Geht das überhaupt bzw. geht das mit PHP?
Mit PHP: Da müsstest Du schon eine eigene Erweiterung schreiben. Denn PHP selbst kann so etwas nicht. PHP kennt AFAIK nicht mal die Linuxthreads-Implementierung, sondern nur die "normalen" Prozessfunktionen. (ich kann mich aber auch täuschen)
Heißt das man sollte das bei Linux doch lieber lassen?
Wie gesagt, PHP kennt sowieso nur Pozessfunktionen, aber keine Threads, und dann macht es keinen Unterschied.
Ja, aber das ändert ja erstmal nicht daran das die CPU damit auch nicht schneller wird. Wird da also irgendwo was gespart.
Nein, aber eine CPU unterstützt das Betriebsystem im Multitasking. Während eine Aktion läuft, kann umgeschaltet werden, so dass diese Aktion unterbrochen wird, bis dieser Prozess wieder drankommt.
Ich kenne mich da jetzt wirklich nicht aus, nur, wenn ich jetzt PHP verwende, also ich erstelle 10 Kinderprozesse, greifen diese Prozesse dann alle über die gegebenen Schnittstellen direkt auf OS-Funkionene zu, z.B. um einen HTTP-Request abzusenden? ich hatte jetzt gedacht das da der PHP Interpreter oder sowas noc dazwischen hängt, aber das Script ist ja, wenn es bereits ausgeführt wird schon interpretiert, oder?
Natürlich hängt PHP dazwischen, aber jedes Mal eine andere PHP-Instanz, weil das alles andere Prozesse sind.
Wenn ich in einem Script in einer schleife fsockopen, fputs("GET..."), fclose verwende, läuft die Schleife erst weiter, wenn die Antwort vom Server gekommen ist, wenn ich das auf mehrere Prozesse verteile, können alle (fast) gleichzeitig anfangen, ohne auf andere Prozesse Rücksicht nehmen zu müssen.
Genau.
Grüße,
Christian