Asynchrones PHP: Swoole und ReactPHP im Vergleich
AI generated
<?php
8.4
PHP · Async · Swoole · ReactPHP
Asynchrones PHP: Swoole und ReactPHP als Alternative
zum klassischen Request-Response-Modell

PHP-FPM verarbeitet Requests synchron und blockierend, ein Modell, das für klassische Webanwendungen bewährt ist, bei WebSockets, Queue-Workern und hoher I/O-Last aber an Grenzen stößt. Asynchrones PHP mit Swoole oder ReactPHP nutzt Event-Loops und Coroutinen, um tausende parallele Verbindungen in einem einzigen Prozess zu verwalten, ohne dabei die Sprache PHP zu verlassen.

16 Min. Lesezeit Swoole · ReactPHP · Event-Loop · Coroutinen PHP 8.4

1. Warum klassisches PHP synchron arbeitet

Das klassische Ausführungsmodell von PHP ist an den HTTP-Request-Response-Zyklus gebunden. Ein Webserver wie nginx nimmt eine Anfrage entgegen und reicht sie über FastCGI an einen PHP-FPM-Worker-Prozess weiter. Dieser Worker führt das Skript vollständig aus, gibt eine Antwort zurück und steht danach für den nächsten Request wieder zur Verfügung. Jede blockierende Operation, ein Datenbank-Query, ein HTTP-Call an eine externe API, eine Dateisystem-Operation, hält den gesamten Worker-Prozess an. Während der Worker auf die Antwort wartet, kann er keinen anderen Request bearbeiten.

Dieses Modell ist bewusst so gebaut, weil es Zustand pro Request isoliert und damit außergewöhnlich robust gegen Fehler in einzelnen Anfragen ist. Stürzt ein Request ab, wird nur ein einziger Worker beendet und vom Process Manager neu gestartet, der Rest der Anwendung läuft unbeeinflusst weiter. Skalierung erfolgt horizontal über die Anzahl der Worker-Prozesse: mehr gleichzeitige Requests bedeuten mehr Worker, mehr Speicherverbrauch und mehr CPU-Kontextwechsel. Bei klassischen, kurzlebigen Web-Requests mit überschaubarer I/O-Wartezeit funktioniert das hervorragend und ist der Grund, warum PHP-FPM seit Jahrzehnten das Rückgrat produktiver PHP-Anwendungen bildet.

Problematisch wird dieses Modell erst, wenn viele Verbindungen lange offen bleiben oder viel Zeit mit Warten statt Rechnen verbracht wird. Ein WebSocket-Server mit zehntausend gleichzeitigen Verbindungen würde in einem reinen PHP-FPM-Modell zehntausend dauerhaft belegte Worker-Prozesse benötigen, jeder mit eigenem Speicher-Overhead. Genau an dieser Stelle setzt asynchrones PHP an: Statt einen Prozess pro Verbindung zu blockieren, verwaltet ein einzelner Prozess über eine Event-Loop tausende Verbindungen gleichzeitig, indem er niemals auf eine einzelne I/O-Operation wartet, sondern zwischen bereiten Aufgaben wechselt.

2. Event-Loop-Grundlagen: wie asynchrones PHP technisch funktioniert

Der zentrale Baustein von asynchronem PHP ist die Event-Loop. Statt eine I/O-Operation synchron auszuführen und auf ihr Ergebnis zu warten, registriert der Code eine Callback-Funktion für den Moment, in dem die Operation abgeschlossen ist, und kehrt sofort zur Event-Loop zurück. Die Event-Loop selbst ist im Kern eine Endlosschleife, die kontinuierlich prüft, welche registrierten I/O-Ressourcen, Dateideskriptoren, Sockets oder Timer, gerade bereit sind, und die zugehörigen Callbacks ausführt. Dieses Prinzip heißt non-blocking I/O: Der Prozess blockiert nie auf eine einzelne Operation, sondern fragt aktiv ab, was gerade Aufmerksamkeit braucht.

Technisch beruht das auf Betriebssystem-Mechanismen wie select(), poll() oder dem effizienteren epoll() unter Linux. Diese Systemaufrufe erlauben es, mehrere Dateideskriptoren gleichzeitig zu überwachen und blockieren nur so lange, bis mindestens einer davon lesbar oder schreibbar ist, statt jeden einzeln nacheinander abzufragen. PHP selbst bringt mit der Stream-API und Funktionen wie stream_select() bereits die Grundbausteine für non-blocking I/O mit, auch ohne zusätzliche Extension. ReactPHP baut direkt darauf auf, während Swoole eine eigene, in C geschriebene Event-Loop mit Coroutinen-Unterstützung mitbringt, die deutlich performanter ist als eine reine PHP-Implementierung.

Wichtig für das Verständnis von asynchronem PHP ist, dass eine Event-Loop grundsätzlich single-threaded arbeitet. Es läuft zu jedem Zeitpunkt nur ein Stück PHP-Code, es gibt also keine klassischen Race Conditions durch parallelen Speicherzugriff, wie man sie aus Multithreading kennt. Parallelität entsteht ausschließlich dadurch, dass zwischen wartenden Operationen umgeschaltet wird, während tatsächliche Berechnung strikt sequenziell bleibt. Das macht asynchrones PHP für I/O-lastige Workloads extrem effizient, aber ungeeignet, um reine CPU-Last auf mehrere Kerne zu verteilen, dafür braucht es weiterhin separate Prozesse oder Threads.


<?php
declare(strict_types=1);

// Minimal illustrative event loop concept using stream_select().
// This is not production code, it demonstrates the core mechanism
// behind asynchronous PHP: never block on a single stream.

$sockets = [/* array of non-blocking stream resources */];
$callbacks = [];

function registerCallback(array &$callbacks, $socket, callable $onReadable): void
{
    $callbacks[(int) $socket] = $onReadable;
}

// The event loop: runs until there is nothing left to watch
while (!empty($sockets)) {
    $read = $sockets;
    $write = null;
    $except = null;

    // Blocks only until at least one socket is ready, not per-socket
    $ready = stream_select($read, $write, $except, 5);

    if ($ready === false) {
        break; // interrupted by a signal, handle and continue in real code
    }

    foreach ($read as $socket) {
        $callback = $callbacks[(int) $socket] ?? null;
        if ($callback !== null) {
            $callback($socket); // run only the code for the ready socket
        }
    }
}

3. ReactPHP im Detail: Event-Loop, Promises und Streams

ReactPHP ist eine reine PHP-Bibliothek, keine Server-Extension, und lässt sich daher in jedem PHP-Projekt per Composer installieren, ohne die PHP-Installation selbst zu verändern. Das Kernpaket react/event-loop stellt die zentrale Event-Loop bereit, an die sich Timer, Stream-Watcher und Signal-Handler anmelden lassen. Alle anderen ReactPHP-Komponenten, HTTP-Server, Socket-Client, DNS-Resolver, Kindprozess-Verwaltung, sind darauf aufgebaut und teilen sich dieselbe Loop-Instanz. Das Ergebnis ist ein modulares Ökosystem, bei dem man nur die Pakete einbindet, die man tatsächlich braucht.

Asynchrone Operationen in ReactPHP werden über Promises modelliert, umgesetzt im Paket react/promise. Eine Promise repräsentiert das zukünftige Ergebnis einer Operation, die noch nicht abgeschlossen ist, und bietet Methoden wie then(), um Callbacks für Erfolg und Fehlerfall zu registrieren. Anders als bei synchronem Code, wo ein Rückgabewert sofort vorliegt, wird bei asynchronem PHP mit ReactPHP der Kontrollfluss über verkettete Callbacks ausgedrückt. Seit PHP 8.1 lässt sich das mit Fibern kombinieren, sodass sich Promise-Ketten auch in einem synchron aussehenden Stil mit await()-ähnlichen Hilfsfunktionen schreiben lassen, was den klassischen Callback-Verschachtelungen entgegenwirkt.

Streams sind das dritte zentrale Konzept: react/stream abstrahiert lesbare und schreibbare Datenströme, etwa für HTTP-Bodies, Dateien oder TCP-Verbindungen, und feuert Events wie data, end oder error, sobald neue Daten verfügbar sind. Dieses Design erlaubt es, große Datenmengen zu verarbeiten, ohne sie vollständig im Speicher zu halten, ein Vorteil gegenüber vielen synchronen PHP-APIs, die auf vollständig gepufferte Strings setzen. Für Entwickler, die aus dem klassischen PHP-FPM-Umfeld kommen, ist ReactPHP oft der sanftere Einstieg in asynchrones PHP, weil keine Server-Extension installiert werden muss und der Code in gewohnter PHP-Syntax bleibt.


<?php
declare(strict_types=1);

require 'vendor/autoload.php';

use React\EventLoop\Loop;
use React\Http\Browser;

// A simple timer registered on the global event loop
Loop::addPeriodicTimer(10.0, function (): void {
    echo "Heartbeat: still running\n";
});

// Asynchronous HTTP request, returns a Promise instead of blocking
$browser = new Browser();

$browser->get('https://api.example.com/status')
    ->then(function (Psr\Http\Message\ResponseInterface $response): void {
        // Runs once the response arrives, without blocking the loop
        echo "Status: " . $response->getStatusCode() . "\n";
    })
    ->catch(function (Throwable $error): void {
        // Runs on failure, network error or non-2xx handling upstream
        echo "Request failed: " . $error->getMessage() . "\n";
    });

// Nothing above blocks execution, the loop keeps running until
// there are no more pending timers or I/O watchers left
Loop::run();

4. Swoole im Detail: Coroutinen und das Server-Modell

Swoole verfolgt einen fundamental anderen Ansatz als ReactPHP: Es ist eine in C geschriebene PHP-Extension, die einen vollständigen, langlebigen Server-Prozess bereitstellt, statt eine reine Bibliothek zu sein. Ein Swoole-Server startet einen Master-Prozess, der wiederum mehrere Worker-Prozesse verwaltet. Jeder Worker kann über Coroutinen tausende gleichzeitige Anfragen bearbeiten, ohne dass für jede Anfrage ein eigener Betriebssystem-Prozess oder -Thread nötig ist. Das reduziert den Speicher- und Kontextwechsel-Overhead drastisch im Vergleich zum klassischen PHP-FPM-Modell mit einem Prozess pro Request.

Coroutinen sind leichtgewichtige, kooperative Ausführungseinheiten innerhalb eines einzigen PHP-Prozesses. Sobald eine Coroutine auf eine I/O-Operation trifft, etwa einen Datenbank-Query oder einen HTTP-Call über eine Swoole-kompatible Client-Bibliothek, gibt sie automatisch die Kontrolle an den Coroutine-Scheduler zurück, der eine andere bereite Coroutine ausführt. Sobald das I/O-Ergebnis vorliegt, wird die ursprüngliche Coroutine an genau der Stelle fortgesetzt, an der sie pausiert hat. Aus Entwicklersicht sieht der Code dabei fast wie klassisches, synchrones PHP aus, obwohl im Hintergrund vollständig asynchrones PHP mit non-blocking I/O abläuft, ein großer Vorteil gegenüber der expliziten Callback-Verkettung.

Damit dieser Mechanismus funktioniert, müssen I/O-Aufrufe coroutine-fähig sein. Swoole bietet dafür sogenanntes Runtime-Hooking (Swoole\Runtime::enableCoroutine()), das Standardfunktionen wie PDO, curl, fopen oder Redis transparent durch coroutine-sichere Implementierungen ersetzt. Ohne dieses Hooking blockiert ein klassischer, synchroner Aufruf innerhalb einer Coroutine den gesamten Worker-Prozess, und alle anderen Coroutinen in diesem Worker müssen warten, ein Detail, das im nächsten Abschnitt zu den Fallstricken vertieft wird.


<?php
declare(strict_types=1);

use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;

// Swoole HTTP server, one process handles thousands of coroutines
$server = new Server('0.0.0.0', 9501);

$server->set([
    'worker_num' => 4,       // number of worker processes
    'enable_coroutine' => true,
]);

$server->on('request', function (Request $request, Response $response): void {
    // Each request runs inside its own coroutine automatically
    $userId = (int) ($request->get['id'] ?? 0);

    // With runtime hooking enabled, this PDO call yields the
    // coroutine instead of blocking the worker process
    $pdo = new PDO('mysql:host=db;dbname=shop', 'app', 'secret');
    $stmt = $pdo->prepare('SELECT name FROM customer WHERE id = ?');
    $stmt->execute([$userId]);
    $row = $stmt->fetch();

    $response->header('Content-Type', 'application/json');
    $response->end(json_encode($row ?: ['error' => 'not found']));
});

$server->start();

5. Typische Anwendungsfälle für asynchrones PHP

WebSocket-Server sind das naheliegendste Einsatzgebiet für asynchrones PHP, weil sie per Definition dauerhaft offene Verbindungen erfordern, für die das klassische PHP-FPM-Modell mit einem Worker pro Verbindung ökonomisch nicht tragbar ist. Chat-Anwendungen, Live-Benachrichtigungen, kollaborative Editoren oder Preis-Ticker in E-Commerce-Systemen lassen sich mit Swoole oder ReactPHP als eigenständiger Prozess neben der bestehenden Anwendung betreiben, der tausende gleichzeitige Verbindungen mit überschaubarem Ressourcenverbrauch verwaltet.

Queue-Worker profitieren ebenfalls stark von asynchronem PHP, insbesondere wenn ein Worker viele externe Services parallel anspricht, etwa beim Versand von Benachrichtigungen an mehrere Kanäle gleichzeitig oder beim Abgleich mit mehreren APIs pro Job. Statt jeden Kanal sequenziell und blockierend abzuarbeiten, lassen sich mit Coroutinen oder Promises mehrere I/O-Operationen parallel anstoßen und gemeinsam auswerten, was die Gesamtlaufzeit pro Job erheblich reduziert. Auch Microservices, die primär als I/O-Vermittler zwischen mehreren Backend-Systemen fungieren, etwa ein Aggregations-Layer, der Daten aus mehreren APIs zusammenführt, profitieren von der hohen Parallelität, die asynchrones PHP ohne zusätzliche Prozesse ermöglicht.

Long-Polling, bei dem eine HTTP-Verbindung absichtlich offengehalten wird, bis neue Daten vorliegen oder ein Timeout erreicht ist, ist ein weiterer klassischer Fall. Im PHP-FPM-Modell würde jede Long-Polling-Verbindung einen Worker für die gesamte Wartezeit blockieren, was die maximale Anzahl gleichzeitiger Clients hart auf die Worker-Anzahl begrenzt. Mit asynchronem PHP kostet eine wartende Verbindung praktisch keine CPU-Zeit, solange kein Event eintritt, wodurch sich die gleiche Hardware für ein Vielfaches an gleichzeitigen Wartezuständen nutzen lässt.


<?php
declare(strict_types=1);

use Swoole\WebSocket\Server;
use Swoole\Http\Request;

// Minimal WebSocket server broadcasting messages to all clients
$server = new Server('0.0.0.0', 9502);

$server->on('open', function (Server $server, Request $request): void {
    echo "Client {$request->fd} connected\n";
});

$server->on('message', function (Server $server, $frame): void {
    // Broadcast the incoming message to every connected client
    foreach ($server->connections as $fd) {
        if ($server->isEstablished($fd)) {
            $server->push($fd, $frame->data);
        }
    }
});

$server->on('close', function (Server $server, int $fd): void {
    echo "Client {$fd} disconnected\n";
});

$server->start();

6. Fallstricke: globaler State, Memory Leaks und blockierende Aufrufe

Der gravierendste Fallstrick bei asynchronem PHP mit Swoole ist die Verwendung globaler oder statischer Variablen zur Zustandshaltung. Anders als bei PHP-FPM, wo jeder Request in einem frischen Prozess startet und der Speicher danach vollständig freigegeben wird, läuft ein Swoole-Worker über tausende Requests hinweg durch, ohne dass PHP zwischendurch neu initialisiert wird. Statische Klassenvariablen oder globale Variablen, die zwischen Requests unbeabsichtigt Zustand teilen, führen zu Bugs, bei denen Daten eines Nutzers plötzlich bei einem anderen Request auftauchen, ein Klassiker aus dem Long-Running-Prozess-Umfeld, den viele PHP-Entwickler aus dem klassischen Request-Response-Modell nicht kennen.

Eng damit verwandt sind Memory Leaks: Da der Prozess nicht nach jedem Request beendet wird, akkumuliert sich Speicher, der nicht korrekt freigegeben wird, über die Laufzeit des Workers. Typische Ursachen sind wachsende Arrays in statischen Properties, nicht geschlossene Datenbankverbindungen oder Event-Listener, die bei jedem Request neu registriert, aber nie entfernt werden. Swoole bietet zwar die Konfigurationsoption max_request, die einen Worker nach einer bestimmten Anzahl Requests automatisch neu startet, das ist aber ein Sicherheitsnetz, kein Ersatz für sauberes Ressourcenmanagement im Code selbst.

Der dritte und für Einsteiger oft überraschendste Fallstrick betrifft blockierende Aufrufe innerhalb von Coroutinen. Ein klassischer sleep()-Aufruf oder ein PDO-Call ohne aktiviertes Runtime-Hooking blockiert den gesamten Worker-Prozess, nicht nur die aktuelle Coroutine. Da ein Worker gleichzeitig hunderte Coroutinen bedient, friert bei einem einzigen blockierenden Aufruf die Bearbeitung aller anderen Anfragen in diesem Worker ein, ein Effekt, der in Lasttests oft erst bei hoher Parallelität auffällt und dann schwer zu diagnostizieren ist.


<?php
declare(strict_types=1);

use Swoole\Coroutine;

Coroutine\run(function (): void {

    // WRONG: blocking sleep() freezes the entire worker process,
    // every other coroutine in this worker has to wait too
    Coroutine::create(function (): void {
        sleep(3); // blocks the OS thread, not coroutine-aware
        echo "Task A done\n";
    });

    // RIGHT: Coroutine::sleep() yields control back to the
    // scheduler, other coroutines keep running in the meantime
    Coroutine::create(function (): void {
        Coroutine::sleep(3.0); // coroutine-safe, non-blocking
        echo "Task B done\n";
    });

    // WRONG: PDO without runtime hooking blocks the worker
    // during the entire query execution time
    Coroutine::create(function (): void {
        $pdo = new PDO('mysql:host=db;dbname=shop', 'app', 'secret');
        $pdo->query('SELECT SLEEP(2)'); // blocks, no coroutine yield
    });

    // RIGHT: enable coroutine hooking once at bootstrap so PDO,
    // curl, streams and Redis become coroutine-safe automatically
    // Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
});

7. Swoole vs. ReactPHP im direkten Vergleich

Swoole und ReactPHP lösen dasselbe Grundproblem, blockierendes I/O in PHP zu vermeiden, mit grundlegend verschiedenen Architekturentscheidungen. Swoole ersetzt den kompletten Server-Prozess und bringt Coroutinen als Sprachfeature nahe, ReactPHP bleibt eine reine Bibliothek, die auf explizite Promises setzt und in jeder bestehenden PHP-Umgebung installierbar ist. Diese Entscheidung hat direkte Konsequenzen für Performance, Lernkurve und wie leicht sich asynchrones PHP in ein bestehendes Projekt integrieren lässt.

Kriterium Swoole ReactPHP
Architekturmodell C-Extension mit eigenem Server-Prozess und Coroutinen-Scheduler Reine PHP-Bibliothek, Event-Loop plus Promises, kein eigener Prozess-Typ
Performance bei hoher Parallelität Sehr hoch, native Coroutinen mit minimalem Overhead pro Verbindung Gut, aber durch reines PHP und Promise-Overhead spürbar langsamer als Swoole
Lernkurve Mittel bis hoch: Coroutinen-Semantik, Hooking und Worker-Konfiguration müssen verstanden werden Niedriger für PHP-Entwickler: Promises und Callbacks statt neuer Ausführungsmodelle
Ökosystem und Erweiterungen Eigene Swoole-kompatible Clients für MySQL, Redis, HTTP, WebSocket, gRPC Modulare Pakete für HTTP, DNS, Prozesse, Streams, breite Composer-Integration
Kompatibilität mit bestehendem Code Erfordert Runtime-Hooking, klassische blockierende Bibliotheken oft problematisch Hoch: läuft neben bestehendem PHP-FPM-Code, keine Extension-Installation nötig
Einsatz in Produktion Verbreitet für Hochlast-APIs, WebSocket-Server und Microservices in Asien und international Verbreitet für leichte Async-Aufgaben, CLI-Tools und Integrationen ohne Extension-Zwang

In der Praxis entscheidet oft die Infrastruktur über die Wahl: Wenn eine Extension installiert werden darf und maximale Performance bei sehr hoher Parallelität gefragt ist, ist Swoole die konsequentere Wahl. Wenn asynchrones PHP nur punktuell für einen Teilbereich einer Anwendung gebraucht wird und keine Kontrolle über die Server-Umgebung besteht, etwa in geteilten Hosting-Umgebungen, ist ReactPHP oft die pragmatischere Option, weil es sich als reine Composer-Abhängigkeit installieren lässt.

8. Asynchrones PHP schrittweise in bestehende Anwendungen integrieren

Ein vollständiger Rewrite einer bestehenden PHP-FPM-Anwendung auf asynchrones PHP ist in den seltensten Fällen sinnvoll oder überhaupt nötig. Der pragmatische Ansatz ist, asynchrones PHP gezielt für die Teile einzuführen, die tatsächlich von hoher Parallelität oder dauerhaften Verbindungen profitieren, während der Rest der Anwendung unverändert auf PHP-FPM weiterläuft. Ein WebSocket-Server für Live-Benachrichtigungen etwa lässt sich als separater Swoole- oder ReactPHP-Prozess neben der bestehenden Webanwendung betreiben, der über eine Message-Queue oder eine interne API mit dem klassischen PHP-FPM-Teil kommuniziert.

Diese Trennung hat mehrere Vorteile: Das Risiko für die bestehende Anwendung bleibt minimal, weil der neue asynchrone Prozess isoliert läuft und bei Problemen unabhängig neu gestartet werden kann, ohne den Rest der Anwendung zu beeinträchtigen. Entwicklerteams können sich schrittweise mit den Eigenheiten von asynchronem PHP vertraut machen, an einem klar abgegrenzten Teilsystem, statt die gesamte Codebasis auf einmal umzustellen. Gleichzeitig lässt sich der Erfolg des neuen Ansatzes anhand konkreter Metriken messen, etwa der Anzahl gleichzeitig gehaltener Verbindungen oder der Latenz bei Push-Benachrichtigungen, bevor eine Entscheidung über eine breitere Einführung getroffen wird.

Bei der Integration ist wichtig, klare Grenzen zwischen den beiden Welten zu ziehen: Der asynchrone Prozess sollte keine gemeinsam genutzten PHP-Klassen mit versteckter Blocking-I/O importieren, die für den PHP-FPM-Kontext geschrieben wurden, ohne sie auf Coroutine-Sicherheit zu prüfen. Konfigurationswerte, Sessions und Zustand sollten über externe Systeme wie Redis oder eine Datenbank geteilt werden, statt über gemeinsam genutzten PHP-Prozessspeicher, weil die beiden Prozesswelten unabhängig voneinander laufen und skalieren. So bleibt asynchrones PHP ein ergänzendes Werkzeug für spezifische Probleme, statt eine riskante Grundsatzentscheidung für das gesamte System.

9. Performance-Erwartungen realistisch einordnen

Asynchrones PHP bringt den größten Vorteil bei I/O-bound Workloads, also Aufgaben, bei denen der Großteil der Zeit mit Warten auf Netzwerk, Datenbank oder Dateisystem verbracht wird, nicht mit tatsächlicher CPU-Berechnung. Ein Endpunkt, der mehrere externe APIs parallel abfragt und die Ergebnisse zusammenführt, profitiert massiv von Coroutinen oder Promises, weil die Wartezeiten überlappen statt sich zu addieren. Ein einzelner Request, der auf drei APIs mit je 200 Millisekunden Antwortzeit wartet, dauert mit Parallelisierung etwa 200 Millisekunden statt 600 Millisekunden im sequenziellen, blockierenden Modell.

Bei CPU-bound Workloads, etwa komplexe Berechnungen, Bildverarbeitung oder große Datenaggregationen ohne wesentliche I/O-Wartezeit, bringt asynchrones PHP dagegen wenig bis gar keinen Vorteil, weil eine Event-Loop nach wie vor single-threaded arbeitet. Eine rechenintensive Coroutine blockiert die Event-Loop für alle anderen Coroutinen im selben Worker genauso, wie es ein blockierender I/O-Call ohne Hooking tun würde. Für solche Fälle braucht es weiterhin echte Parallelität über mehrere Prozesse, etwa über zusätzliche Swoole-Worker oder ausgelagerte Queue-Jobs, nicht über Coroutinen innerhalb eines einzigen Prozesses.

Realistisch betrachtet lohnt sich der Umstieg auf asynchrones PHP dann, wenn die Anzahl gleichzeitiger Verbindungen oder die I/O-Wartezeit pro Request signifikant genug ist, dass klassisches PHP-FPM an Speicher- oder Worker-Grenzen stößt. Für die meisten klassischen CRUD-Webanwendungen mit überschaubarer gleichzeitiger Last bringt PHP-FPM weiterhin ausreichend Performance bei deutlich geringerer Komplexität. Der Umstieg sollte daher immer durch konkrete Zahlen begründet sein, gemessene Latenzen, Worker-Auslastung, Anzahl gleichzeitiger Verbindungen, statt durch die Annahme, dass asynchrones PHP grundsätzlich schneller ist.

10. Zusammenfassung

Asynchrones PHP mit Swoole oder ReactPHP löst ein spezifisches Problem des klassischen PHP-FPM-Modells: die ineffiziente Bindung eines ganzen Worker-Prozesses an eine einzelne, oft wartende Verbindung. Über Event-Loops, non-blocking I/O und, im Fall von Swoole, Coroutinen lassen sich tausende gleichzeitige Verbindungen in einem einzigen Prozess verwalten, ohne bei jeder I/O-Operation einen vollständigen Prozess zu blockieren. ReactPHP bietet dabei den pragmatischeren Einstieg als reine Bibliothek, Swoole die höhere Performance und Coroutinen-Nähe als vollwertiger Server-Prozess.

Der Erfolg beim Einsatz von asynchronem PHP hängt entscheidend davon ab, die typischen Fallstricke zu kennen: globaler Zustand in Long-Running-Prozessen, Memory Leaks über die Lebenszeit eines Workers und blockierende Aufrufe innerhalb von Coroutinen ohne Runtime-Hooking. Wer asynchrones PHP schrittweise und gezielt für I/O-lastige Teilprobleme einführt, statt die gesamte Anwendung umzuschreiben, bekommt die Vorteile hoher Parallelität, ohne das Risiko eines riskanten Komplett-Rewrites einzugehen.

Asynchrones PHP mit Swoole und ReactPHP - Das Wichtigste auf einen Blick

Grundproblem

PHP-FPM blockiert einen ganzen Worker pro Request. Asynchrones PHP verwaltet tausende Verbindungen in einem einzigen Prozess über eine Event-Loop.

Swoole vs. ReactPHP

Swoole: C-Extension, eigener Server-Prozess, Coroutinen, höchste Performance. ReactPHP: reine Bibliothek, Promises, einfachere Integration.

Typische Fallstricke

Globaler Zustand über Requests hinweg, Memory Leaks im Long-Running-Prozess, blockierende Calls in Coroutinen ohne Hooking.

Wann es sich lohnt

Bei I/O-bound Workloads mit hoher Parallelität, WebSockets, Queue-Workern. Bei CPU-bound Aufgaben bringt es kaum Vorteile.

11. FAQ: Asynchrones PHP mit Swoole und ReactPHP

1Was bedeutet asynchrones PHP genau?
Ein Ausführungsmodell ohne blockierende I/O-Operationen. Statt auf eine Antwort zu warten, registriert der Code einen Callback, die Event-Loop kümmert sich zwischenzeitlich um andere Aufgaben.
2Ersatz für PHP-FPM?
Nein, eine Ergänzung für WebSockets oder Queue-Worker mit hoher I/O-Last. Für klassische Web-Requests bleibt PHP-FPM meist einfacher und ausreichend.
3Swoole vs. ReactPHP?
Swoole: C-Extension, eigener Server-Prozess, native Coroutinen. ReactPHP: reine PHP-Bibliothek mit Promises, ohne Extension-Zwang per Composer nutzbar.
4Was sind Coroutinen?
Leichtgewichtige, kooperative Ausführungseinheiten in einem Prozess. Bei I/O-Wartezeit geben sie die Kontrolle automatisch an den Scheduler zurück.
5Warum blockiert PDO trotzdem?
Ohne Runtime-Hooking ist PDO nicht coroutine-fähig und blockiert den ganzen Worker. Swoole\Runtime::enableCoroutine() ersetzt PDO transparent durch eine coroutine-sichere Variante.
6Muss ich komplett umschreiben?
Nein, ein separater Prozess für einen abgegrenzten Teilbereich, etwa einen WebSocket-Server, neben der bestehenden PHP-FPM-Anwendung ist der pragmatische Ansatz.
7Vorteil bei CPU-Last?
Kaum. Die Event-Loop ist single-threaded, eine rechenintensive Coroutine blockiert alle anderen im selben Worker. Für CPU-bound Aufgaben braucht es echte Prozess-Parallelität.
8Typische Bugs mit Swoole?
Globaler oder statischer Zustand, der unbeabsichtigt zwischen Requests geteilt wird, sowie Memory Leaks durch nicht freigegebene Ressourcen über die Worker-Lebenszeit.
9Beste Anwendungsfälle?
WebSocket-Server, Long-Polling, Queue-Worker mit vielen parallelen API-Calls und Microservices, die Daten aus mehreren Backends aggregieren.
10Swoole in Produktion stabil?
Ja, international in Hochlast-Systemen im Einsatz. Entscheidend ist, die Fallstricke rund um Coroutinen und Runtime-Hooking von Anfang an zu berücksichtigen.

Mironsoft

PHP-Architektur, Performance-Engineering und Magento-Entwicklung

Zu viele blockierende Prozesse in eurer PHP-Anwendung?

Wir analysieren, wo asynchrones PHP mit Swoole oder ReactPHP tatsächlich Mehrwert bringt, und integrieren es gezielt neben eurer bestehenden PHP-FPM- oder Magento-Infrastruktur, statt einen riskanten Komplett-Rewrite vorzuschlagen.

Architektur-Review

Analyse, ob Swoole, ReactPHP oder klassisches PHP-FPM für euren Anwendungsfall die richtige Wahl ist

WebSocket & Worker

Aufbau isolierter asynchroner Prozesse für Live-Features und Queue-Worker neben bestehendem Code

Performance-Audit

Messung von I/O-Wartezeiten und Worker-Auslastung als Entscheidungsgrundlage vor jeder Migration