Función PHP mysqli_poll()
Aprende la función PHP mysqli_poll(): sintaxis, parámetros, valores de retorno y cómo consultar conexiones MySQL asíncronas con un ejemplo completo.
La función mysqli_poll() te permite esperar en varias conexiones MySQL al mismo tiempo y averiguar cuáles de ellas han terminado de ejecutar una consulta asíncrona. Es el puente entre lanzar consultas no bloqueantes y recoger sus resultados sin bloquear todo el script en la más lenta.
Qué hace mysqli_poll()
Cuando ejecutas una consulta de la forma habitual, PHP se detiene y espera hasta que MySQL responde. Con las consultas asíncronas (iniciadas con el indicador MYSQLI_ASYNC), la consulta se envía pero el script continúa ejecutándose. El problema entonces es: ¿cómo sé cuándo un resultado está listo para leer? Eso es lo que responde mysqli_poll().
Le pasas una lista de conexiones y bloquea hasta que al menos una de ellas tenga un resultado esperando (o hasta que se agote un tiempo de espera). Luego te indica qué conexiones están listas y obtienes sus resultados con reap_async_query().
Esto importa cuando necesitas ejecutar varias consultas independientes en paralelo — por ejemplo, consultar dos bases de datos diferentes o ejecutar varios informes lentos a la vez. En lugar de pagar el coste de cada consulta una tras otra, las lanzas todas y las dejas ejecutarse de forma concurrente.
Importante: mysqli_poll() solo funciona con el controlador mysqlnd. No está disponible con el antiguo controlador libmysql. Además, es solo procedural — no existe un método orientado a objetos $mysqli->poll(); siempre se llama como mysqli_poll(...).
Sintaxis
mysqli_poll(
array &$read,
array &$error,
array &$reject,
int $seconds,
int $microseconds = 0
): int|falseParámetros
| Parámetro | Descripción |
|---|---|
$read | Lista de conexiones a comprobar para ver si tienen resultados. Se pasa por referencia — al retornar se reescribe para contener solo las conexiones que tienen un resultado listo. |
$error | Se reescribe para contener las conexiones en las que se produjo un error. |
$reject | Se reescribe para contener las conexiones que fueron rechazadas (sin consulta asíncrona pendiente en ellas). |
$seconds | Número máximo de segundos a esperar. |
$microseconds | Microsegundos adicionales a esperar (opcional, por defecto 0). |
Valor de retorno
Devuelve el número de conexiones listas en caso de éxito, o false en caso de fallo. Un retorno de 0 significa que el tiempo de espera se agotó antes de que ninguna conexión estuviera lista — no es un error.
Cómo usar la función mysqli_poll()
El patrón siempre son los mismos tres pasos:
- Abre una conexión por consulta que quieras ejecutar en paralelo.
- Inicia cada consulta con el indicador
MYSQLI_ASYNCpara que no bloquee. - Itera llamando a
mysqli_poll()para esperar a la conexión que termine primero y recupera su resultado.
<?php
// Open one connection per parallel query.
$conn1 = new mysqli("localhost", "user", "pass", "shop");
$conn2 = new mysqli("localhost", "user", "pass", "shop");
foreach ([$conn1, $conn2] as $c) {
if ($c->connect_errno) {
exit("Connect failed: " . $c->connect_error);
}
}
// Fire both queries asynchronously — neither call blocks.
$conn1->query("SELECT SLEEP(1), 'orders done' AS msg", MYSQLI_ASYNC);
$conn2->query("SELECT SLEEP(2), 'reports done' AS msg", MYSQLI_ASYNC);
$pending = [$conn1, $conn2];
while (!empty($pending)) {
// Copies that mysqli_poll() will rewrite by reference.
$read = $pending;
$error = $pending;
$reject = $pending;
// Block up to 5 seconds for at least one connection to become ready.
if (mysqli_poll($read, $error, $reject, 5) === false) {
echo "Poll failed.\n";
break;
}
// $read now holds only the connections with a result waiting.
foreach ($read as $conn) {
if ($result = $conn->reap_async_query()) {
$row = $result->fetch_assoc();
echo $row['msg'] . "\n";
$result->free();
} else {
echo "Query error: " . $conn->error . "\n";
}
// Remove this connection from the pending list.
$pending = array_filter($pending, fn($c) => $c !== $conn);
}
}
$conn1->close();
$conn2->close();
?>Aunque la primera consulta duerme 1 segundo y la segunda 2 segundos, el script completo termina en aproximadamente 2 segundos, no en 3 — las dos consultas se ejecutaron al mismo tiempo. Como la consulta de 1 segundo termina primero, la salida es:
orders done
reports doneLo que hace el código, paso a paso
- Abrimos dos conexiones porque cada conexión solo puede ejecutar una consulta asíncrona a la vez.
query(..., MYSQLI_ASYNC)envía cada consulta y regresa inmediatamente en lugar de esperar.- Antes de cada llamada a
mysqli_poll()copiamos$pendingen$read,$errory$reject, porque la función reescribe esos arrays por referencia.$readvuelve conteniendo solo las conexiones listas,$errorlas fallidas y$rejectcualquiera sin consulta pendiente. - Por cada conexión lista llamamos a
reap_async_query()para recoger el conjunto de resultados, luego eliminamos esa conexión de$pendingpara no consultarla de nuevo. - El bucle termina una vez que todas las consultas han sido recogidas.
Nota: Para cargas de trabajo asíncronas complejas, considera bibliotecas de bucle de eventos como ReactPHP o Swoole, que proporcionan arquitecturas más robustas que implementar un bucle de sondeo a mano.
Funciones relacionadas
reap_async_query()— recoge el resultado de una conexión quemysqli_poll()indicó como lista.query()— ejecuta una consulta (añadeMYSQLI_ASYNCpara hacerla no bloqueante).multi_query()— ejecuta varias sentencias en una sola llamada sobre una única conexión.connect_errno— comprueba si un intento de conexión falló.
Conclusión
mysqli_poll() es la pieza que hace que las consultas MySQL paralelas sean prácticas en PHP: espera en muchas conexiones a la vez y te dice cuáles están listas para leer. Combínala con consultas MYSQLI_ASYNC y reap_async_query(), recuerda que necesita el controlador mysqlnd, y podrás reducir el tiempo total de varias consultas independientes a aproximadamente el tiempo de la más lenta.