Fiber in PHP 8.1: concorrenza cooperativa senza async/await
new Fiber(), suspend() e resume(): le basi delle coroutine, spiegate senza tecnicismi
Fino a PHP 8.0, il tuo codice avanzava sempre in fila indiana: una riga alla volta, senza modo di mettere in pausa una funzione e tornarci più tardi. Altri linguaggi risolvono questo problema con le parole chiave async e await. PHP 8.1 prende una strada diversa e più "artigianale": la classe Fiber, che permette di sospendere e riprendere l'esecuzione di un blocco di codice a mano, senza aggiungere nuove parole riservate al linguaggio.
Fiber è come un segnalibro la cui posizione la scegli tu. Stai leggendo un romanzo (il tuo codice) e a un certo punto ti fermi esattamente a pagina 45: il segnalibro ricorda la pagina, i personaggi, il filo del discorso. Nessuno ti strappa il libro di mano a metà frase, sei tu, dall'interno della lettura, a scegliere quando fermarti. Ma per riaprire il libro e continuare, deve essere qualcun altro a rimettertelo in mano.
- Sospendibile: puoi fermare l'esecuzione in un punto preciso e ripartire da lì, con tutte le variabili intatte.
- Cooperativo: un Fiber si mette in pausa da solo, ma non riparte da solo: deve essere il codice esterno a farlo ripartire.
- Con uno stack proprio: a differenza dei Generator, ogni Fiber porta con sé la propria pila di chiamate.
1. Si crea con new Fiber(), non con un thread
Un Fiber si crea passando una funzione anonima al costruttore: new Fiber(callable $callback). Attenzione: crearlo non lo avvia. E soprattutto, un Fiber non è un thread del sistema operativo, non gira davvero in parallelo. È un meccanismo di pausa e ripresa interamente gestito dal tuo codice PHP, un singolo processo alla volta.
$fiber = new Fiber(function (): void {
echo "Fiber avviato\n";
$valore = Fiber::suspend('sono in pausa');
echo "Fiber ripreso con: $valore\n";
});
// a questo punto il fiber esiste ma non ha ancora eseguito una riga
Fonte: PHP Manual: «The Fiber class», Fiber::__construct() (php.net/manual/en/class.fiber.php).
2. start(): il primo via
Il metodo start(mixed ...$args) avvia davvero l'esecuzione. Il codice del Fiber gira finché non incontra un Fiber::suspend() oppure finché non termina: quel valore (o null se il Fiber finisce senza sospendersi) diventa il risultato di start() per chi lo ha chiamato.
$ricevuto = $fiber->start();
echo "Il chiamante riceve: $ricevuto\n";
// Output:
// Fiber avviato
// Il chiamante riceve: sono in pausa
Fonte: PHP Manual: Fiber::start() (php.net/manual/en/fiber.start.php).
3. suspend() e resume(): un dialogo a due voci
Da dentro il Fiber si chiama il metodo statico Fiber::suspend($valore): mette in pausa e restituisce $valore a chi ha chiamato start() o resume(). Da fuori, si chiama $fiber->resume($valore): il Fiber riparte esattamente da dove si era fermato, e quel $valore diventa il risultato della Fiber::suspend() che lo aveva messo in pausa. I due metodi si passano dati avanti e indietro come due persone che si passano la linea al telefono.
$fiber->resume('bentornato');
// dentro il fiber, $valore ora contiene 'bentornato':
// Output: Fiber ripreso con: bentornato
E' come dire al telefono «resto in linea, un attimo» (suspend): la chiamata non si chiude, resta tutto il contesto della conversazione. Solo l'altra persona può farti ripartire dicendo «ci sono, rieccomi» (resume) e in quel momento può anche darti un'informazione nuova, che tu ricevi esattamente nel punto in cui ti eri fermato.
4. Uno stack tutto suo: la differenza con i Generator
PHP aveva già un modo per "mettere in pausa" del codice: i Generator con yield. Ma un Generator può sospendersi solo nella funzione che contiene lo yield, non in una funzione chiamata al suo interno. Un Fiber invece è "full-stack": porta con sé una pila di chiamate indipendente, quindi puoi chiamare Fiber::suspend() anche dentro una funzione annidata, a più livelli di profondità, senza che il chiamante debba saperlo o cambiare il proprio codice.
function operazionePesante(): mixed {
// può sospendersi anche qui, in una funzione annidata
return Fiber::suspend('sto aspettando dei dati');
}
$fiber = new Fiber(function (): void {
$dati = operazionePesante();
echo "Ho ricevuto: $dati\n";
});
$fiber->start();
$fiber->resume('dati pronti');
Un Generator è come un cuoco che tiene un solo segnaposto sulla ricetta principale: se manda un aiutante a fare un passaggio altrove, perde traccia di dove si trovava. Un Fiber è come dare a quel cuoco un taccuino personale che segue ogni passaggio, anche quelli delegati agli aiutanti: può fermarsi in qualunque punto della catena e ritrovare tutto al proprio posto quando riparte.
5. Chi decide quando riprendere? Nessuno, finché non lo scrivi tu
Qui sta la parola "cooperativo": un Fiber si sospende da solo, ma non riparte mai da solo. Deve essere codice esterno a chiamare resume() (o throw() per rilanciare un'eccezione al suo interno). I Fiber, da soli, non fanno nulla di automatico: sono il meccanismo di pausa/ripresa, non l'orchestratore. È esattamente questo il mattone su cui librerie come ReactPHP, Amphp e Revolt costruiscono i propri event loop per offrire I/O non bloccante senza bisogno di async/await nel linguaggio.
In sintesi
| Metodo | Chi lo chiama | Cosa fa |
|---|---|---|
new Fiber($cb) |
Codice esterno | Crea il Fiber, non lo avvia |
$fiber->start(...$args) |
Codice esterno | Avvia; ritorna al primo suspend() o a fine esecuzione |
Fiber::suspend($val) |
Dentro il Fiber | Mette in pausa; $val torna a start()/resume() |
$fiber->resume($val) |
Codice esterno | Riprende; $val diventa il ritorno di suspend() |
$fiber->getReturn() |
Codice esterno | Legge il return, solo a Fiber terminato |
isSuspended() / isRunning() / isTerminated() |
Codice esterno | Controllano lo stato del Fiber |
I Fiber non sostituiscono async/await: gli danno un fondamento. Nella maggior parte dei casi non li scriverai a mano ogni giorno, li userai indirettamente, attraverso una libreria asincrona. Ma ora sai cosa succede davvero quando quella libreria mette in pausa il tuo codice.
Commenti (0)
Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).
Nessun commento. Sii il primo a scrivere qualcosa.