Fibers en PHP 8.1: concurrencia cooperativa sin async/await

Las Fibers de PHP 8.1 son rutinas ligeras que permiten pausar la ejecución de una función y reanudarla más tarde desde el mismo punto, sin usar hilos del sistema operativo. Son el bloque de construcción de las librerías de concurrencia cooperativa como Revolt y Amp, que las usan internamente para implementar async/await.

Conceptos básicos: crear, iniciar, pausar y reanudar

<?php
$fiber = new Fiber(function (): void {
    echo "Fiber: antes de suspendn";

    $valor = Fiber::suspend('primer yield');

    echo "Fiber: recibí '$valor' tras el primer suspendn";

    Fiber::suspend('segundo yield');

    echo "Fiber: terminandon";
});

$resultado1 = $fiber->start();         // inicia la fiber
echo "Main: fiber devolvió '$resultado1'n"; // primer yield

$resultado2 = $fiber->resume('hola'); // reanuda, pasando 'hola' como valor
echo "Main: fiber devolvió '$resultado2'n"; // segundo yield

$fiber->resume(); // reanuda por última vez, la fiber termina
?>

Salida:

Fiber: antes de suspend
Main: fiber devolvió 'primer yield'
Fiber: recibí 'hola' tras el primer suspend
Main: fiber devolvió 'segundo yield'
Fiber: terminando

Estado de una Fiber

<?php
$fiber = new Fiber(function (): string {
    Fiber::suspend();
    return 'resultado final';
});

var_dump($fiber->isStarted());    // false
var_dump($fiber->isSuspended());  // false

$fiber->start();

var_dump($fiber->isStarted());    // true
var_dump($fiber->isSuspended());  // true
var_dump($fiber->isRunning());    // false
var_dump($fiber->isTerminated()); // false

$fiber->resume();

var_dump($fiber->isTerminated()); // true
echo $fiber->getReturn(); // resultado final
?>

Ejemplo real: leer múltiples ficheros sin bloquear

<?php
function leerFicheroFiber(string $ruta): Fiber
{
    return new Fiber(function () use ($ruta): void {
        // Simular lectura asíncrona (en producción sería I/O real no bloqueante)
        Fiber::suspend("leyendo: $ruta");

        $contenido = file_get_contents($ruta);
        Fiber::suspend("leído: " . strlen($contenido ?? '') . " bytes de $ruta");
    });
}

$fibers = [
    leerFicheroFiber('/etc/hostname'),
    leerFicheroFiber('/etc/os-release'),
];

// Iniciar todas
foreach ($fibers as $f) {
    echo $f->start() . "n";
}

// Reanudar todas
foreach ($fibers as $f) {
    echo $f->resume() . "n";
}
?>

Cómo Revolt usa las Fibers internamente

Revolt es el loop de eventos que usa Amp v3. Su modelo es: cada operación await suspende la Fiber actual y cede el control al loop, que ejecuta otras Fibers hasta que la operación de I/O completa y la reanuda:

<?php
// Ejemplo conceptual (requiere revolt/event-loop)
// composer require revolt/event-loop

use RevoltEventLoop;

EventLoop::queue(function (): void {
    $fiber = new Fiber(function (): void {
        echo "Tarea A: inicion";
        Fiber::suspend();
        echo "Tarea A: finn";
    });

    $fiber->start();

    echo "Tarea B: ejecutándose mientras A está suspendidan";

    $fiber->resume();
});

EventLoop::run();
// Tarea A: inicio
// Tarea B: ejecutándose mientras A está suspendida
// Tarea A: fin
?>

Diferencias con generators

Característica

Generator

Fiber

Puede estar en la pila de llamadas

No

Suspensión desde funciones anidadas

No

Puede pasar valor al reanudar

Sí (send)

Sí (resume)

Uso principal

Iteración lazy

Concurrencia cooperativa

La documentación oficial de Fiber en PHP describe la API completa de la clase, los estados posibles y las restricciones de uso (no se puede usar dentro de otra Fiber sin un loop de eventos).

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP