PHP (Pseudo-) Threading

Bewertung [ Bewertung abgeben ] Artikel geschrieben am 25.03.2021 um 17:48 Uhr, aktualisiert am 22.07.2023, um 21:29 Uhr.

Für die Umsetzung nehmen wir das Beispiel der Cronjobs. Früher gab es viele Hosting-Verträge, in denen oft nur ein Cronjob enthalten war. Zu diesen Zeiten war das Pseudo-Threading erheblich wertvoller, immerhin konnte man so mehr Aufgaben automatisch durchführen als eigentlich geplant bzw. erlaubt durch den Hoster.

nser Konzept wird vorsehen eine zentrale PHP-Datei cron.php aufzurufen. Diese soll weitere Aufgaben selbstständig starten.

Für die einzelnen Aufgaben bauen wir uns eine PHP-Datei taskX.php, die über den Parameter ?task=X zu einer bestimmten Aufgabe wird.

Auf einem echten Hoster könnte ein Cronjob angelegt werden, der jede Minute die Datei cron.php aufruft. Natürlich kann die Datei auch manuell ausgeführt werden. In der Praxis sollte man bedenken, dass ein zyklisches Anstoßen der Datei nicht absolut gesichert ist. Das geht in 99% der Fälle gut, aber im Pseudo-Threading ist es wichtig, dass eine doppelte Ausführung der Aufgaben unterbunden wird. Im Beispiel wird man diesen Umstand erkennen, allerdings sollte die Zuverlässigkeit in einer produktiven Umgebung mit anderen Mitteln umgesetzt werden.
Spätestens in einem Cluster-Betrieb der Webseite sollte man mindestens auf eine Datenbankstruktur ausweichen.

Um das Beispiel einfach zu halten, schreiben die einzelnen Aufgaben in eine Zeile in eine Protokoll-Datei, die sich alle Prozesse teilen werden. Gleichzeitig schreiben sie auch eine gesonderte Datei nur für die Aufgabe selbst.

Um eine Doppelausführung zu verhindern, wird am zu Beginn eine spezielle Datei erstellt und am Ende der Aufgabe wieder entfernt. Bei der Ausführung wird also zuerst kurz geprüft, ob die Datei vorhanden ist und falls ja, beendet sich die Ausführung, ohne etwas zu tun.

Durch diesen Prozess ist es theoretisch möglich, dass auch ein Deadlock stattfindet, falls die Sperr-Datei nicht korrekt aufgeräumt wird. Wie man sieht, erzeugen Threads ein deutlich höherer Aufwand in der Programmierung, denn die komplette Prozesskontrolle muss an die übliche Handhabung von Threads angenähert werden. Eine vollständige Prozesskontrolle ist (fast) unmöglich und würde einen derart hohen Aufwand in der Umsetzung bedeuten, dass man ggf. Alternativen in Betracht ziehen sollte. Für die meisten alltäglichen Fälle sollte es allerdings ausreichen.

Um die doppelte Ausführung testen zu können, werden wir das Skript nach der Ausgabe, mithilfe der Funktion sleep(), in eine Pause schicken. Auch wenn unsere Anwendung nichts mehr Produktives anstellt, ist das in einem echten Programm durchaus realistisch.