Fibers
Fibers son una caracteristica de PHP 8.1 que permite la ejecucion concurrente cooperativa. Son la base para bibliotecas asincronas y rara vez se usan directamente.
¿Que son los Fibers?
Un Fiber es un bloque de codigo que puede pausarse y reanudarse. A diferencia de los hilos, los Fibers son cooperativos: el codigo decide cuando cede el control.
<?php
declare(strict_types=1);
$fiber = new Fiber(function (): void {
echo "1. Inicio del Fiber\n";
// Pausar y devolver control al llamador
$valor = Fiber::suspend('pausado');
echo "3. Reanudado con: $valor\n";
});
// Iniciar el Fiber
$resultado = $fiber->start();
echo "2. Fiber pausado, retorno: $resultado\n";
// Reanudar el Fiber
$fiber->resume('datos del exterior');
echo "4. Fiber terminado\n";
// Salida:
// 1. Inicio del Fiber
// 2. Fiber pausado, retorno: pausado
// 3. Reanudado con: datos del exterior
// 4. Fiber terminado
Metodos principales
<?php
declare(strict_types=1);
$fiber = new Fiber(function (): string {
$entrada = Fiber::suspend('esperando');
return "Resultado: $entrada";
});
// start(): inicia el Fiber, retorna lo que suspend() envia
$suspendido = $fiber->start();
// resume($valor): reanuda pasando un valor
$retorno = $fiber->resume('hola');
// getReturn(): obtiene el valor retornado
echo $fiber->getReturn(); // "Resultado: hola"
// Estados del Fiber
$fiber2 = new Fiber(fn () => Fiber::suspend());
echo $fiber2->isStarted(); // false
echo $fiber2->isSuspended(); // false
echo $fiber2->isRunning(); // false
echo $fiber2->isTerminated(); // false
$fiber2->start();
echo $fiber2->isSuspended(); // true
Caso de uso: multiples tareas
<?php
declare(strict_types=1);
function crearTarea(string $nombre, int $pasos): Fiber
{
return new Fiber(function () use ($nombre, $pasos): string {
for ($i = 1; $i <= $pasos; $i++) {
echo "$nombre: paso $i de $pasos\n";
Fiber::suspend();
}
return "$nombre completada";
});
}
// Crear varias tareas
$tareas = [
crearTarea('Tarea A', 3),
crearTarea('Tarea B', 2),
crearTarea('Tarea C', 4),
];
// Iniciar todas
foreach ($tareas as $tarea) {
$tarea->start();
}
// Ejecutar en "paralelo" (intercalando)
while (true) {
$activas = array_filter($tareas, fn ($f) => !$f->isTerminated());
if (empty($activas)) {
break;
}
foreach ($activas as $tarea) {
if ($tarea->isSuspended()) {
$tarea->resume();
}
}
}
// Salida intercalada:
// Tarea A: paso 1 de 3
// Tarea B: paso 1 de 2
// Tarea C: paso 1 de 4
// Tarea A: paso 2 de 3
// ...
Uso en la práctica
En la practica, raramente usaras Fibers directamente. Son la base para bibliotecas como:
- ReactPHP: programacion asincrona orientada a eventos
- Amp: concurrencia con promesas y coroutines
- Swoole: servidor HTTP de alto rendimiento
<?php
declare(strict_types=1);
// Esto es pseudo-codigo para ilustrar el concepto
// En la practica, usarias una biblioteca como Amp
/*
use Amp\async;
use Amp\Future;
// Con bibliotecas basadas en Fibers
$resultados = Future\await([
async(fn () => fetchUrl('https://api1.example.com')),
async(fn () => fetchUrl('https://api2.example.com')),
async(fn () => fetchUrl('https://api3.example.com')),
]);
// Las 3 peticiones se ejecutan "en paralelo"
// Fibers permiten que mientras una espera respuesta,
// las otras pueden continuar
*/
Fibers son una caracteristica de bajo nivel. Para la mayoria de casos, usaras bibliotecas que los aprovechan internamente. No necesitas entender Fibers en profundidad para usar PHP 8.
Ejercicios
Ejercicio 1: Fiber basico
Crea un Fiber que cuente del 1 al 5, suspendiendo despues de cada numero. El codigo principal debe imprimir un separador entre cada reanudacion.
Ver solucion
<?php
declare(strict_types=1);
$contador = new Fiber(function (): void {
for ($i = 1; $i <= 5; $i++) {
echo "Numero: $i\n";
if ($i < 5) {
Fiber::suspend();
}
}
});
$contador->start();
while ($contador->isSuspended()) {
echo "---\n";
$contador->resume();
}
echo "Fin\n";
Ejercicio 2: Comunicacion bidireccional
Crea un Fiber que reciba numeros via resume()
y los acumule. Cuando reciba 0, debe terminar y retornar
la suma total.
Ver solucion
<?php
declare(strict_types=1);
$sumador = new Fiber(function (): int {
$suma = 0;
while (true) {
$numero = Fiber::suspend($suma);
if ($numero === 0) {
return $suma;
}
$suma += $numero;
}
});
$sumador->start();
$sumador->resume(10); // suma = 10
$sumador->resume(20); // suma = 30
$sumador->resume(5); // suma = 35
$sumador->resume(0); // termina
echo "Total: " . $sumador->getReturn(); // 35
¿Has encontrado un error o tienes una sugerencia?
Escribenos