Hochleistungsserver mit Swoole
Bedienen Sie Tausende von Verbindungen mit Coroutine-basiertem Swoole.
Hochleistungsserver mit Swoole ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Was Swoole ist
Swoole (und sein Fork OpenSwoole) ist eine C-Erweiterung, die PHP in eine hochperformante, Coroutine-basierte und ereignisgesteuerte Laufzeitumgebung verwandelt. Statt dass PHP-FPM pro Anfrage einen Prozess startet, initialisiert ein Swoole-Server Ihre Anwendung einmal und hält sie resident im Speicher. Anfragen werden von einem Pool langlebiger Worker mit integrierten Coroutinen verarbeitet. Das Ergebnis: Durchsatzsteigerungen um Größenordnungen und native Nebenläufigkeit innerhalb einer einzigen Anfrage.
Der persistente HTTP-Server
Das klassische Beispiel: ein vollständiger HTTP-Server in einem Skript. Er lauscht, verteilt jede Anfrage an einen Worker und initialisiert das Framework nicht erneut. Beachten Sie, dass hierfür ext-swoole erforderlich ist – der Server läuft nicht mit der standardmäßigen PHP-CLI.
<?php
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set(['worker_num' => 4]);
$server->on('request', function ($request, $response) {
$response->header('Content-Type', 'application/json');
$response->end(json_encode(['hello' => $request->server['request_uri']]));
});
echo "listening on :9501\n";
$server->start();Coroutinen statt Callbacks
Die herausragende Funktion von Swoole sind Coroutinen: Sie schreiben sequenziellen Code im Stil blockierender Aufrufe, den die Laufzeitumgebung kooperativ einplant. Coroutine\run() öffnet einen Coroutine-Kontext; go() startet eine neue Coroutine. Jede Coroutine verfügt über einen eigenen Stack wie ein Fiber, aber Swoole plant sie an I/O-Punkten automatisch ein.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () { Co::sleep(1); echo "A done\n"; });
go(function () { Co::sleep(1); echo "B done\n"; });
// Both sleep concurrently -> total ~1s, not 2s
});Abgefangene blockierende Funktionen
Das Geheimnis hinter der einfachen Verwendung von Coroutinen sind Runtime-Hooks. Swoole wandelt blockierende Aufrufe – PDO, Redis, curl, sleep, file_get_contents – transparent in nicht blockierende, Coroutine-fähige Varianten um. Ihr gewöhnliches $pdo->query() gibt die Ausführung an die Coroutine ab, statt den Worker einzufrieren.
<?php
use Swoole\Runtime;
use Swoole\Coroutine as Co;
Runtime::enableCoroutine(SWOOLE_HOOK_ALL); // hook PDO, curl, sleep, etc.
Co\run(function () {
go(function () { sleep(1); echo "task 1\n"; }); // sleep() is now async!
go(function () { sleep(1); echo "task 2\n"; });
}); // finishes in ~1s because sleep was hookedNebenläufige I/O mit WaitGroup
Um Arbeit aufzufächern und anschließend zusammenzuführen, bietet Swoole eine WaitGroup (ähnlich wie Go's sync.WaitGroup). Starten Sie Coroutinen, rufen Sie pro Aufgabe add() auf, bei Abschluss done() und mit wait(), um zu warten, bis alle Aufgaben nebenläufig abgeschlossen sind.
<?php
use Swoole\Coroutine as Co;
use Swoole\Coroutine\WaitGroup;
Co\run(function () {
$wg = new WaitGroup();
$results = [];
foreach (['eu', 'us', 'asia'] as $region) {
$wg->add();
go(function () use ($wg, $region, &$results) {
Co::sleep(0.5); // simulated API call
$results[$region] = "ok-$region";
$wg->done();
});
}
$wg->wait(); // all three ran in parallel (~0.5s)
var_dump($results);
});Channels zur Kommunikation
Coroutinen koordinieren sich über Channels – typisierte, begrenzte Warteschlangen, die den Produzenten bei voller Warteschlange und den Konsumenten bei leerer Warteschlange anhalten. Dabei handelt es sich um Nachrichtenübermittlung nach dem CSP-Modell, wodurch Sperren für gemeinsam genutzten Zustand vollständig vermieden werden.
<?php
use Swoole\Coroutine as Co;
use Swoole\Coroutine\Channel;
Co\run(function () {
$chan = new Channel(2);
go(function () use ($chan) {
foreach (range(1, 3) as $n) $chan->push($n);
$chan->push(null); // sentinel
});
go(function () use ($chan) {
while (($v = $chan->pop()) !== null) echo "got $v\n";
});
});Verbindungspooling
Ein persistenter Server sollte nicht pro Anfrage eine Datenbankverbindung öffnen. Swoole stellt Coroutine-sichere Verbindungspools bereit, damit Worker über Tausende nebenläufiger Coroutinen hinweg einen festen Satz von Verbindungen wiederverwenden und das ständige Öffnen und Schließen von Verbindungen entfällt.
<?php
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Coroutine as Co;
Co\run(function () {
$pool = new PDOPool((new PDOConfig())
->withHost('127.0.0.1')->withDbname('app')
->withUsername('u')->withPassword('p'), 8);
go(function () use ($pool) {
$pdo = $pool->get(); // borrow
$row = $pdo->query('SELECT NOW()')->fetch();
$pool->put($pdo); // return to pool
var_dump($row);
});
});Zustandslecks: Die Falle des persistenten Speichers
Da der Prozess anfragenübergreifend weiterläuft, bleibt globaler und statischer Zustand erhalten. Ein statischer Cache, der unbeschränkt wächst, ein Singleton mit anfragespezifischen Daten oder eine nicht freigegebene Datenbanktransaktion kann spätere Anfragen beeinträchtigen und den Speicher erschöpfen. Regeln: Vermeiden Sie anfragebezogene Daten in statischen Variablen und Singletons, setzen Sie den Kontext pro Anfrage zurück und konfigurieren Sie max_request, damit Worker regelmäßig neu gestartet werden.
<?php
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set([
'worker_num' => 8,
'max_request' => 10000, // recycle a worker after N requests to bound leaks
]);
// Never store $request data in a static property between requests!Coroutine-lokaler Kontext
Da ein Worker viele Coroutinen ineinander verschachtelt ausführt, können Sie für anfragebezogene Daten keine einfachen statischen Variablen verwenden. Swoole gibt jeder Coroutine einen eigenen Kontext (Coroutine::getContext()) – ein Objekt, dessen Lebensdauer an die Coroutine gebunden ist und das sich ideal für den aktuellen Benutzer, die Anfrage-ID oder ein Transaktions-Handle eignet.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () {
$ctx = Co::getContext();
$ctx['request_id'] = 'req-123';
// ... deep call chain can read Co::getContext()['request_id']
echo Co::getContext()['request_id'], PHP_EOL;
});
});Prozessmodell und Task-Worker
Swoole führt einen Master-Prozess (verwaltet Event-Loop-Threads), einen Manager (startet und überwacht Worker), Worker-Prozesse (führen Ihre Request-Handler und Coroutinen aus) sowie optionale Task-Worker für umfangreiche, blockierende oder CPU-intensive Aufgaben aus, die über $server->task() ausgelagert werden. Verwenden Sie Task-Worker für Bildverarbeitung oder lange CPU-intensive Aufgaben, damit diese die Anfrage-Coroutinen nicht aufhalten – so erhalten Sie sowohl Nebenläufigkeit als auch Parallelität.
Defer und Timer
Swoole ermöglicht es Ihnen, mit Coroutine::defer() Arbeit einzuplanen, die nach Abschluss der aktuellen Coroutine ausgeführt wird – ideal, um Ressourcen aus Verbindungspools auch bei ausgelösten Exceptions zuverlässig freizugeben. Serverweite Timer (Timer::tick) führen periodische Aufgaben wie die Aktualisierung des Caches innerhalb eines Workers aus, ohne dass ein externer Cron benötigt wird.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () {
$conn = 'borrowed-connection';
Co::defer(function () use ($conn) {
echo "released $conn\n"; // runs when coroutine exits, even on error
});
echo "using $conn\n";
});
});Schnelltest
Warum müssen Sie es vermeiden, Anfrage-Daten in statischen Eigenschaften eines Swoole-Servers zu speichern?
Zusammenfassung
Swoole verwandelt PHP in einen residenten, von Coroutinen gesteuerten Server:
- Die Anwendung wird einmal initialisiert; ein Worker-Pool verarbeitet Anfragen mit integrierten Coroutinen (
Co\run/go()). - Runtime-Hooks machen gewöhnliche Aufrufe von PDO/curl/sleep nicht blockierend; WaitGroup und Channels koordinieren nebenläufige Arbeit.
- Verbindungspools verwenden Datenbankverbindungen über mehrere Coroutinen hinweg wieder.
- Persistenter Speicher bedeutet, dass Sie Zustandslecks vermeiden müssen: Verwenden Sie
Coroutine::getContext()für anfragebezogene Daten, setzen Siemax_requestund lagern Sie umfangreiche Aufgaben an Task-Worker aus.
Häufig gestellte Fragen
Ist die Lektion „Hochleistungsserver mit Swoole“ kostenlos?
Ja — der vollständige Text von „Hochleistungsserver mit Swoole“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Hochleistungsserver mit Swoole“?
Bedienen Sie Tausende von Verbindungen mit Coroutine-basiertem Swoole. Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um PHP Academy zu starten?
Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Hochleistungsserver mit Swoole“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?
Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Das PHP-Konkurrenzmodell
- PHP 8.1 Fibers
- Event Loops mit ReactPHP
- Hochleistungsserver mit Swoole