Implementando Coroutines con Fibers en PHP 8.1+
PHP 8.1 introdujo las Fibers, un mecanismo de concurrencia ligero que permite implementar coroutines. Las coroutines son funciones que pueden suspender su ejecución y retomarla más tarde, sin necesidad de crear nuevos hilos o procesos. Esto permite escribir código asíncrono de manera más legible y eficiente que con callbacks o promesas.
Este post explora cómo implementar coroutines con Fibers para manejar operaciones de E/S concurrentes, como múltiples solicitudes HTTP, de forma eficiente y no bloqueante. Utilizaremos la extensión cURL para realizar las solicitudes HTTP.
<?php
use Fiber;
/**
* Función para realizar una solicitud HTTP asíncrona usando cURL y Fibers.
*
* @param string $url La URL a solicitar.
* @return string|false El contenido de la respuesta o false en caso de error.
*/
function async_http_get(string $url): string|false
{
$fiber = Fiber::getCurrent(); // Obtener la Fiber actual
if (!$fiber) {
throw new LogicException("Esta función debe ser llamada dentro de una Fiber.");
}
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 5); // Timeout de 5 segundos
// Callback para ejecutar cuando cURL necesite leer/escribir
curl_setopt($ch, CURLOPT_READFUNCTION, function ($ch, $fd, $length) use ($fiber) {
// Ceder el control a la Fiber principal
Fiber::suspend();
return ''; // cURL necesita un valor de retorno, aunque sea vacío
});
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
/**
* Wrapper para ejecutar una coroutine dentro de una Fiber.
*
* @param callable $callable La coroutine a ejecutar.
* @return mixed El resultado de la coroutine.
*/
function run(callable $callable): mixed
{
$fiber = new Fiber($callable);
return $fiber->start();
}
El código anterior define dos funciones clave: `async_http_get` y `run`. La función `async_http_get` utiliza la extensión cURL para realizar solicitudes HTTP de forma asíncrona. Dentro de la función, `Fiber::suspend()` cede el control a la Fiber principal, permitiendo que otras coroutines se ejecuten. La función `run` crea una nueva Fiber y la ejecuta.
<?php
require_once 'fibers.php'; // Incluir el código anterior
$urls = [
'https://www.example.com',
'https://www.php.net',
'https://www.google.com',
];
$responses = [];
$fibers = [];
// Iniciar las Fibers para cada URL
foreach ($urls as $url) {
$fibers[$url] = new Fiber(function () use ($url, &$responses) {
$responses[$url] = async_http_get($url);
echo "Completado: $url\n";
});
$fibers[$url]->start();
}
// Gestionar la ejecución de las Fibers
while (count($fibers) > 0) {
foreach ($fibers as $url => $fiber) {
if ($fiber->isSuspended()) {
$fiber->resume(); // Reanudar la Fiber
}
if ($fiber->isTerminated()) {
unset($fibers[$url]); // Eliminar la Fiber completada
}
}
}
// Imprimir las respuestas (opcional)
// var_dump($responses);
Este ejemplo muestra cómo iniciar múltiples Fibers para realizar solicitudes HTTP concurrentes. El bucle `while` gestiona la ejecución de las Fibers, reanudándolas cuando están suspendidas y eliminándolas cuando están terminadas. Esto permite que las solicitudes se realicen de forma concurrente sin bloquear el hilo principal.
En conclusión, las Fibers en PHP 8.1+ ofrecen una forma poderosa y eficiente de implementar coroutines para manejar operaciones de E/S concurrentes. Esta técnica puede mejorar significativamente el rendimiento de aplicaciones que realizan muchas operaciones de red.
No hay comentarios:
Publicar un comentario