reap_async_query
Aprenda como mysqli_reap_async_query() obtém resultados de consultas assíncronas no PHP, com exemplo prático usando mysqli_poll.
Introdução
mysqli_reap_async_query() recupera o resultado de uma consulta iniciada de forma assíncrona com a extensão MySQLi. Uma consulta assíncrona é aquela que você dispara sem esperar o servidor terminar — seu script PHP continua executando, e você coleta o resultado mais tarde, quando o servidor sinaliza que está pronto.
Esta é a peça que falta no fluxo de trabalho assíncrono do MySQLi. Por si só, mysqli_reap_async_query() não faz nada útil: ela só faz sentido como etapa final de um padrão de três partes composto por mysqli_query(..., MYSQLI_ASYNC) (ou mysqli_send_query()), mysqli_poll() e mysqli_reap_async_query(). Esta página explica como essas peças se encaixam, apresenta um exemplo completo e executável, e lista os erros comuns que pegam as pessoas de surpresa.
Requisito: consultas assíncronas só funcionam com o driver mysqlnd (o driver nativo padrão nas versões modernas do PHP). Elas não estão disponíveis quando o MySQLi é compilado contra o antigo
libmysqlclient.
O ciclo de vida da consulta assíncrona
Uma única consulta assíncrona passa por três etapas:
- Enviar — inicia a consulta com a flag
MYSQLI_ASYNC.mysqli_query($conn, $sql, MYSQLI_RESULT, MYSQLI_ASYNC)(ou a forma abreviadamysqli_send_query()) retorna imediatamente sem esperar pelos resultados. - Aguardar — chame
mysqli_poll()para esperar até que uma ou mais conexões tenham um resultado pronto. É aqui que ocorre o bloqueio (com um timeout que você controla), em vez de bloquear na própria consulta. - Coletar — assim que a sondagem indicar que uma conexão está pronta, chame
mysqli_reap_async_query($conn)para buscar omysqli_resultdessa conexão.
A razão pela qual isso importa é a etapa de sondagem. Você pode colocar várias conexões em uma única chamada mysqli_poll() e fazer com que todas as suas consultas sejam executadas no servidor ao mesmo tempo. O tempo de espera total fica em torno do tempo da consulta mais lenta, não da soma de todas elas.
mysqli_poll(): a parte que não pode ser pulada
Um erro comum é chamar mysqli_reap_async_query() diretamente após enviar uma consulta. Se o resultado ainda não estiver pronto, a coleta retorna false e define um erro — ela não espera. mysqli_poll() é a função que espera.
mysqli_poll() recebe arrays de conexões passadas por referência e um timeout:
mysqli_poll($read, $error, $reject, $sec, $usec);$read— um array das conexões que você deseja monitorar. Após a chamada, ele é reduzido apenas às conexões que têm um resultado aguardando.$error/$reject— recebem conexões com erros de protocolo ou requisições rejeitadas.$sec/$usec— quanto tempo esperar, em segundos e microssegundos.
Retorna o número de conexões prontas (0 em timeout, false em falha).
Exemplo completo: executar duas consultas em paralelo
O exemplo abaixo abre duas conexões, dispara uma consulta assíncrona em cada uma, aguarda até que os resultados cheguem e coleta cada um. Substitua as credenciais e o SQL pelos seus.
<?php
// One connection per concurrent query.
$conn1 = mysqli_connect("localhost", "user", "password", "shop");
$conn2 = mysqli_connect("localhost", "user", "password", "shop");
// 1. Send both queries asynchronously — neither call blocks.
mysqli_query($conn1, "SELECT COUNT(*) AS n FROM orders", MYSQLI_STORE_RESULT, MYSQLI_ASYNC);
mysqli_query($conn2, "SELECT COUNT(*) AS n FROM customers", MYSQLI_STORE_RESULT, MYSQLI_ASYNC);
$links = [$conn1, $conn2];
$pending = count($links);
// 2. Poll until every connection has reported back.
while ($pending > 0) {
$read = $error = $reject = $links;
// Wait up to 1 second for any connection to become ready.
if (!mysqli_poll($read, $error, $reject, 1)) {
continue; // timeout — nothing ready yet, loop again
}
// 3. Reap each ready connection.
foreach ($read as $link) {
$result = mysqli_reap_async_query($link);
if ($result) {
$row = mysqli_fetch_assoc($result);
echo "Count: " . $row["n"] . "\n";
mysqli_free_result($result);
} else {
echo "Query error: " . mysqli_error($link) . "\n";
}
$pending--;
}
}
?>Cada conexão só pode executar uma consulta assíncrona por vez — é por isso que o exemplo usa uma conexão separada por consulta. Reutilize uma conexão para uma nova consulta assíncrona somente após ter coletado o resultado anterior.
Resumo passo a passo
- Abra uma conexão por consulta que você deseja executar simultaneamente (
mysqli_connect()). - Inicie cada consulta com a flag
MYSQLI_ASYNCpara que a chamada retorne imediatamente. - Colete as conexões em um array e passe-o para
mysqli_poll()com um timeout. - Para cada conexão que
mysqli_poll()indicar como pronta, chamemysqli_reap_async_query(). - Processe o
mysqli_resultretornado e libere-o commysqli_free_result().
Valores de retorno e tratamento de erros
mysqli_reap_async_query() retorna:
- Um objeto
mysqli_resultpara consultas que produzem um conjunto de resultados (por ex.,SELECT). truepara consultas que não retornam linhas (INSERT,UPDATE,DELETE) quando bem-sucedidas.falseem caso de falha ou quando chamada antes do resultado estar pronto — verifiquemysqli_error()nesse caso.
Sempre preceda a coleta com mysqli_poll(). Coletar uma conexão que não está pronta é a fonte mais comum de retornos false misteriosos.
Casos de uso para consultas não bloqueantes no MySQLi
Consultas não bloqueantes no MySQLi são úteis para desenvolvedores PHP que precisam executar múltiplas consultas em paralelo ou consultas de longa duração sem bloquear a execução de outros códigos. Aqui estão alguns casos de uso práticos para essa abordagem:
1. Execução de consultas em paralelo
Desenvolvedores podem usar consultas não bloqueantes do MySQLi para executar múltiplas consultas independentes em paralelo. Ao enviar cada consulta com mysqli_send_query() e intercalar outra lógica, as aplicações podem reduzir o tempo de espera total ao buscar dados de múltiplas tabelas ou serviços.
2. Consultas de longa duração
Consultas de longa duração podem ser iniciadas de forma assíncrona para que o script PHP possa lidar com outras tarefas, como registro de logs, atualizações de interface ou processamento de entrada do usuário, enquanto o banco de dados conclui a operação.
3. Aplicações em tempo real
Aplicações que requerem sondagem frequente de dados ou atualizações em tempo real podem iniciar consultas sem congelar a thread de execução principal. Isso é particularmente útil para ferramentas de monitoramento baseadas em CLI ou endpoints web leves que precisam retornar rapidamente.
4. Processamento assíncrono de dados
Desenvolvedores podem delegar tarefas pesadas de recuperação de dados para executar em segundo plano enquanto o script principal processa outros fluxos de dados, melhorando o throughput geral em processamento em lote ou fluxos de trabalho ETL.
Vantagens das consultas não bloqueantes no MySQLi
As consultas não bloqueantes do MySQLi oferecem várias vantagens para desenvolvedores PHP:
1. Melhor desempenho
Ao executar consultas de forma assíncrona, a execução de outros códigos não é bloqueada, resultando em melhor desempenho da aplicação. Isso é especialmente benéfico para aplicações que agregam dados de múltiplas fontes ou lidam com requisições de alta concorrência.
2. Melhor utilização de recursos
A execução não bloqueante permite que o processo PHP permaneça responsivo enquanto aguarda operações do banco de dados, reduzindo o tempo ocioso e melhorando a utilização dos recursos do servidor.
3. Gerenciamento simplificado de tarefas em segundo plano
Desenvolvedores podem encadear múltiplas operações de banco de dados sem aninhar callbacks ou máquinas de estado complexas, tornando o código mais fácil de ler e manter para scripts PHP procedurais padrão.
Conclusão
mysqli_reap_async_query() é a etapa final do fluxo de trabalho de consultas assíncronas do MySQLi: você inicia uma consulta com a flag MYSQLI_ASYNC, aguarda com mysqli_poll() e então coleta o resultado. Usadas em conjunto, essas funções permitem que um script PHP execute várias consultas contra o MySQL em paralelo e colete os resultados conforme eles terminam, em vez de esperar por cada um separadamente. O maior benefício é quando você tem múltiplas consultas independentes — o tempo de espera total cai para aproximadamente o da consulta mais lenta, em vez da soma de todas elas. Lembre-se das duas regras que mantêm isso confiável: uma consulta assíncrona por conexão, e nunca colete antes que mysqli_poll() diga que a conexão está pronta.
Tópicos relacionados
- mysqli_poll — aguarda até que uma ou mais conexões assíncronas estejam prontas.
- mysqli_multi_query — executa várias instruções em uma única chamada.
- mysqli_query — a função de consulta padrão (síncrona).
- mysqli_connect — abre as conexões nas quais você executa consultas.
- PHP MySQLi — visão geral da extensão MySQLi.