Async\Pool Architektur
Dieser Artikel beschreibt das interne Design des universellen Ressourcenpools. Wenn Sie eine Nutzungsanleitung suchen, siehe Async\Pool. Fuer die PDO-spezifische Schicht, siehe PDO Pool Architektur.
Datenstruktur
Der Pool ist in zwei Schichten implementiert: eine oeffentliche ABI-Struktur im PHP-Kern und eine erweiterte interne Struktur in der Async-Erweiterung.
Zwei Erstellungspfade
Ein Pool kann aus PHP-Code (ueber den Async\Pool-Konstruktor)
oder aus einer C-Erweiterung (ueber die interne API) erstellt werden.
| Pfad | Funktion | Callbacks | Verwendet von |
|---|---|---|---|
| PHP | zend_async_pool_create() |
zend_fcall_t* (PHP callable) |
Benutzercode |
| C API | zend_async_pool_create_internal() |
Funktionszeiger | PDO, andere Erweiterungen |
Der Unterschied liegt in handler_flags. Wenn das Flag gesetzt ist, ruft der Pool die C-Funktion direkt auf,
ohne den Overhead des Aufrufens eines PHP callable ueber zend_call_function().
Acquire: Erhalten einer Ressource
Warten auf eine Ressource
Wenn alle Ressourcen belegt sind und max_size erreicht ist, suspendiert die Koroutine
ueber ZEND_ASYNC_SUSPEND(). Der Wartemechanismus aehnelt Channels:
- Eine
zend_async_pool_waiter_t-Struktur wird erstellt - Der Waiter wird zur FIFO-
waiters-Warteschlange hinzugefuegt - Ein Callback zum Aufwecken wird registriert
- Wenn ein Timeout gesetzt ist – wird ein Timer registriert
ZEND_ASYNC_SUSPEND()– die Koroutine gibt die Kontrolle ab
Das Aufwecken erfolgt, wenn eine andere Koroutine release() aufruft.
Release: Zurueckgeben einer Ressource
Healthcheck: Hintergrundueberwachung
Wenn healthcheckInterval > 0, wird beim Erstellen des Pools ein periodischer Timer gestartet.
Der Timer wird ueber ZEND_ASYNC_NEW_TIMER_EVENT in den Reactor integriert.
Der Healthcheck ueberprueft nur freie Ressourcen. Belegte Ressourcen werden nicht beeinflusst.
Wenn nach dem Entfernen toter Ressourcen die Gesamtzahl unter min faellt, erstellt der Pool Ersatz.
Ringpuffer
Freie Ressourcen werden in einem Ringpuffer gespeichert – einem Ring-Buffer mit fester Kapazitaet. Die anfaengliche Kapazitaet betraegt 8 Elemente, die bei Bedarf erweitert wird.
push- und pop-Operationen laufen in O(1). Der Puffer verwendet zwei Zeiger (head und tail),
was ein effizientes Hinzufuegen und Extrahieren von Ressourcen ohne Verschieben von Elementen ermoeglicht.
Integration mit dem Event-System
Der Pool erbt von zend_async_event_t und implementiert einen vollstaendigen Satz von Event-Handlern:
| Handler | Zweck |
|---|---|
add_callback |
Callback registrieren (fuer Waiter) |
del_callback |
Callback entfernen |
start |
Event starten (NOP) |
stop |
Event stoppen (NOP) |
dispose |
Vollstaendige Bereinigung: Speicher freigeben, Callbacks zerstoeren |
Dies ermoeglicht:
- Suspendieren und Fortsetzen von Koroutinen ueber Event-Callbacks
- Integration des Healthcheck-Timers mit dem Reactor
- Ordnungsgemaesse Freigabe von Ressourcen durch Event-Disposal
Garbage Collection
Der PHP-Pool-Wrapper (async_pool_obj_t) implementiert ein benutzerdefiniertes get_gc,
das alle Ressourcen aus dem Idle-Puffer als GC-Roots registriert.
Dies verhindert vorzeitige Garbage Collection freier Ressourcen,
die keine expliziten Referenzen aus PHP-Code haben.
Circuit Breaker
Der Pool implementiert die CircuitBreaker-Schnittstelle mit drei Zustaenden:
Uebergaenge koennen manuell oder automatisch ueber CircuitBreakerStrategy erfolgen:
reportSuccess()wird bei einem erfolgreichenreleaseaufgerufen (Ressource hatbeforeReleasebestanden)reportFailure()wird aufgerufen, wennbeforeReleasefalsezurueckgegeben hat- Die Strategie entscheidet, wann die Zustaende gewechselt werden
Close: Herunterfahren des Pools
Wenn der Pool geschlossen wird:
- Das Pool-Event wird als CLOSED markiert
- Der Healthcheck-Timer wird gestoppt
- Alle wartenden Koroutinen werden mit einer
PoolExceptionaufgeweckt - Alle freien Ressourcen werden ueber
destructorzerstoert - Belegte Ressourcen leben weiter – sie werden bei
releasezerstoert
C API fuer Erweiterungen
Erweiterungen (PDO, Redis usw.) verwenden den Pool ueber Makros:
| Makro | Funktion |
|---|---|
ZEND_ASYNC_NEW_POOL(...) |
Pool mit C-Callbacks erstellen |
ZEND_ASYNC_NEW_POOL_OBJ(pool) |
PHP-Wrapper fuer Pool erstellen |
ZEND_ASYNC_POOL_ACQUIRE(pool, result, timeout) |
Ressource erhalten |
ZEND_ASYNC_POOL_RELEASE(pool, resource) |
Ressource freigeben |
ZEND_ASYNC_POOL_CLOSE(pool) |
Pool schliessen |
Alle Makros rufen Funktionszeiger auf, die von der Async-Erweiterung beim Laden registriert wurden. Dies stellt die Isolation sicher: Der PHP-Kern haengt nicht von der spezifischen Pool-Implementierung ab.
Sequenz: Vollstaendiger Acquire-Release-Zyklus
Was kommt als Naechstes?
- Async\Pool: Anleitung – wie man den Pool verwendet
- PDO Pool Architektur – PDO-spezifische Schicht
- Koroutinen – wie Koroutinen funktionieren